为什么ADL的运算符函数与其他函数的行为不同?

问题描述 投票:1回答:1

我创建了一个 CNS_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

现在,我想创建一个新的类 A 在一个单独的命名空间内 NS_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,呼吁 call 的成员函数。NS_C::C<NS_A> 对象将调用重载的 NS_A::operator+ 因为它更匹配(第二个参数是 intNS_A::operator+longNS_C::C::operator+).然而,我不明白为什么同样的行为没有发生在我的 not_operator 功能。确实如此。NS_C::C::not_operator 仍将从 call 的功能。

让我们使用下面的主函数。

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个回答
3
投票

过载解决#调用一个过载的操作者。:

我们在重载中拥有重载操作符的候选集。

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

2)非成员候选者。对于运算符重载允许非成员形式的运算符,在表达式的上下文中(可能涉及ADL),通过对operator@的非限定名查找发现的所有声明,除了成员函数声明被忽略外,并不妨碍查找继续进入下一个包围范围。如果一个二进制运算符的两个操作数或一个单元运算符的唯一操作数都具有枚举类型,那么从查找集中成为非成员候选函数的只有那些参数具有该枚举类型(或对该枚举类型的引用)的函数。

而对于另一个,我们只有 无条件查询

甚至有一个例子,在 未限定_查询#超载_操作者有别 operator+(a, a)a + a

© www.soinside.com 2019 - 2024. All rights reserved.