依赖于参数的查找在从另一个名称空间别名的类型上出现意外行为

min*_*iot 6 c++ language-lawyer argument-dependent-lookup

我刚刚使用参数依赖查找遇到了一些有趣的行为,我不完全理解:

#include <iostream>

namespace a {
struct Foo {
  Foo(int v1, int v2) : v1(v1), v2(v2) { }
  int v1,v2;
};
}

namespace b {
template <typename T>
struct Baz : T {
  using T::T;
};
}

namespace c {
using Foo = ::b::Baz< ::a::Foo>;

// (1) NOT FOUND BY ADL
// std::ostream& operator << (std::ostream& os, const Foo& foo)
// {
//   return os << foo.v1 << "," << foo.v2;
// }
}

namespace b {

// (2) FOUND BY ADL
std::ostream& operator << (std::ostream& os, const ::c::Foo& foo)
{
  return os << foo.v1 << "," << foo.v2;
}

}

int main()
{
  c::Foo foo(1,2);
  // Variant (1): ADL fails: should it not find
  //   c::operator<<(std::ostream&, const Foo&) ?
  // Variant (2) compiles
  std::cout << "foo: " << foo << std::endl;
}
Run Code Online (Sandbox Code Playgroud)

c::Foo实际上是b::Baz<...>这样,所以当我在里面定义它时,ADL找到运算符是有道理的namespace b.但它似乎无视直觉,定义内部运算符namespace c不起作用,因为c::Foo 应该(IMHO)允许编译器namespace c也在内部执行ADL .

为什么不是这样?这背后的理由是什么?

Col*_*mbo 4

[basic.lookup.argdep]/2

用于指定类型的Typedef 名称和using-declaration不参与此集合。

typedef 名称和 using 声明都与它们指定的类型无关。如果是的话(在我看来,这实际上是违反直觉的),事情就会很容易崩溃;只是因为我对某个类进行了 typedef,所有调用现在都考虑在 typedef 附近添加的函数,这实际上是不需要的:

#include <string>

namespace A {
    using str = std::string;
    int stoi(str); // This will be a candidate in e.g. stoi(std::string{"0.4"}),
                   // leading to potentially different behavior or ambiguity

namespace B {
    int stoi(std::string); // This is no candidate, because...?
}
Run Code Online (Sandbox Code Playgroud)