ADL 对这段 C++ 代码有何影响?

YHS*_*SPY 6 c++ name-lookup argument-dependent-lookup

实际上,使用此命令无法使用 Clang 编译以下代码:

clang++ -std=c++11 test.cc -o test.

我只想模仿与 C++ 中的“交换习语”相同的行为,以使用“使用指令”来启用 ADL。但是下面的代码我哪里错了?预期的呼叫优先级应该是:N1::foo> N2::foo> ::foo,对吗?

namespace N1 {
  struct S {};
  void foo(S s) {
    std::cout << "called N1::foo.";
  }
}
namespace N2 {
  void foo(N1::S s) {
    std::cout << "called N2::foo.";
  }
}
void foo(N1::S s) {
  std::cout << "called foo.";
}
int main() {
  using N2::foo;  
  foo(N1::S{});
}
Run Code Online (Sandbox Code Playgroud)

错误信息:

test.cc:54:3: error: call to 'foo' is ambiguous
  foo(N1::S{});
  ^~~
test.cc:40:8: note: candidate function
  void foo(S s) {
       ^
test.cc:45:8: note: candidate function
  void foo(N1::S s) {
       ^
1 error generated.
Run Code Online (Sandbox Code Playgroud)

更新:

我将 N2::foo 更改为模板方法,该方法可以在一定程度上模仿 std::swap 。那么,这里的问题是为什么::foo不能foo(N1::S{});main函数中被“ ”调用?因为当它们具有相同的优先级时,该函数应该比要调用的模板函数更合适。

namespace N1 {
  struct S {};
  /*
  void foo(S s) {
    std::cout << "called N1::foo, specific one." << '\n';
  }
  */
}
namespace N2 {  // as a fallback to unqualified name which has no user-defined overload.
  template<typename T>
  void foo(T) {
    std::cout << "called N2::foo, generic one." << '\n';
  }
}
void foo(N1::S s) {
  std::cout << "called foo." << '\n';
}
int main() {
  using N2::foo;
  foo(N1::S{});
  foo(10);  // use generic version.
}
Run Code Online (Sandbox Code Playgroud)

son*_*yao 4

在这种情况下,正常名称查找会找到 和N2::foo,并且被ADLN1::foo找到,它们都被添加到重载集中,然后执行重载解析,并且调用是不明确的。

BTW:如果没有using N2::foo;in main()::foo将通过正常的名称查找找到,并且N1::foo也可以通过 ADL 找到;结果,调用仍然不明确。

更新:

那么,这里的问题是为什么函数中不能被“”::foo调用呢?foo(N1::S{});main

因为随着 的使用using N2::foo;,名称N2::foo被引入到main函数中。当调用foo名称时,N2::foo将在 的范围内找到名称main,然后名称查找停止,将不会检查进一步的范围(全局名称空间),因此::foo根本不会被发现并添加到重载集中。N2::foo因为这两种情况都需要结果。

名称查找按如下所述检查范围,直到找到至少一个任何类型的声明,此时查找停止并且不再检查其他范围。

顺便说一句:如果您using N2::foo;在之前放入全局命名空间mainfoo(N1::S{});则会调用::foo. 和N2::foo都是::foo通过名称查找找到的,并::foo在重载解析中获胜。

居住