【问题标题】:Why ADL has a different behavior for operator function than other functions?为什么 ADL 对运算符函数的行为与其他函数不同?
【发布时间】:2020-05-22 12:43:12
【问题描述】:

我以这种方式在NS_C 命名空间内创建了一个C 类:

#include <iostream>

namespace NS_C {
  template <typename T>
  class C {
    public:
      C operator+(long) {
        std::cout << "NS_C::C::operator+\n";
        return *this;
      }

      void not_operator(C<T>, long) {
        std::cout << "NS_C::C::not_operator\n";
      }

      void call() {
        *this + 0;
        not_operator(*this, 0);
      }
  };
}

函数call 应该调用NS_C::C::operator+ 然后NS_C::C::not_operator。为了测试这种行为,我运行了这个小程序:

int main()
{
  NS_C::C<int> ci;
  ci.call();

  return 0;
}

输出是我所期望的:

> g++ -o example example.cpp && ./example
NS_C::C::operator+
NS_C::C::not_operator

现在,我想在单独的命名空间 NS_A 中创建一个新类 A,并向该命名空间添加两个通用重载 operator+not_operator 函数:

#include <iostream>

namespace NS_A {
  class A {};

  template <typename T>
  T operator+(T t, int)
  {
    std::cout << "NS_A::operator+\n";
    return t;
  }

  template <typename T>
  void not_operator(T, int)
  {
    std::cout << "NS_A::not_operator\n";
  }
}

感谢ADL,从NS_C::C&lt;NS_A&gt; 对象调用call 成员函数将调用重载的NS_A::operator+,因为它更好地匹配(第二个参数是NS_A::operator+ 中的intlong NS_C::C::operator+)。 但是,我不明白为什么我的 not_operator 函数不会发生相同的行为。实际上,NS_C::C::not_operator 仍然会从 call 函数中调用。

让我们使用下面的 main 函数:

int main()
{
  NS_C::C<NS_A::A> ca;
  ca.call();

  return 0;
}

我有以下输出:

NS_A::operator+
NS_C::C::not_operator

为什么在这种情况下不调用NS_A::not_operator


这里是重现问题的完整代码:

#include <iostream>

namespace NS_A {
  class A {};

  template <typename T>
  T operator+(T t, int)
  {
    std::cout << "NS_A::operator+\n";
    return t;
  }

  template <typename T>
  void not_operator(T, int)
  {
    std::cout << "NS_A::not_operator\n";
  }
}

namespace NS_C {
  template <typename T>
  class C {
    public:
      C operator+(long) {
        std::cout << "NS_C::C::operator+\n";
        return *this;
      } 

      void not_operator(C<T>, long) {
        std::cout << "NS_C::C::not_operator\n";
      }

      void call() {
        *this + 0;
        not_operator(*this, 0);
      }
  };
}   

int main()
{
  NS_C::C<int> ci;
  ci.call();

  NS_C::C<NS_A::A> ca;
  ca.call();

  return 0;
}

【问题讨论】:

    标签: c++ operator-overloading argument-dependent-lookup


    【解决方案1】:

    来自overload_resolution#Call_to_an_overloaded_operator

    我们有重载运算符的重载候选集:

    1) 候选成员:如果 T1 是一个完整的类或当前正在定义的类,则候选成员集合是 T1::operator@ 的合格名称查找的结果。在所有其他情况下,候选成员集为空。

    2) 非成员候选:对于运算符重载允许非成员形式的运算符,在表达式上下文中通过 operator@ 的非限定名称查找找到的所有声明(可能涉及 ADL),但成员函数声明除外被忽略并且不会阻止查找继续进入下一个封闭范围。如果二元运算符的两个操作数或一元运算符的唯一操作数都具有枚举类型,则查找集中唯一成为非成员候选的函数是其参数具有该枚举类型(或对该枚举类型的引用)的函数

    而对于另一个,我们只有unqualified_lookup

    unqualified_lookup#Overloaded_operator 中甚至还有一个例子 显示operator+(a, a)a + a 之间的区别

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-07-20
      • 2011-02-26
      • 1970-01-01
      • 1970-01-01
      • 2017-04-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多