为什么使用范围解析运算符会更改调用全局命名空间中的哪个重载模板?

Why does using the scope resolution operator change which overloaded template in the global namespace gets called?

考虑以下代码:

#include <iostream>

template <class W, class T>
void foo(W& a, T& t)
{
  std::cout << "generic" << std::endl;
}

template <template <bool> class W, class T>
void foo(W<true>& a, const T& t)
{
  foo(a, const_cast<T&>(t));
}

template <class W>
void foo(W& a, int& t)
{
  std::cout << "int" << std::endl;
}

template <bool> struct what;
template<> struct what<true> { };

int main() {
  const int ci = 10;
  what<true> wt;

  foo(wt, ci);

  return 0;
}

输出为 (ideone link):

int

这对我来说很有意义:foo(what<true>&, const int&) 匹配 const_cast 重载,然后调用 foo(what<true>&, int&),匹配 int 重载。

然而,如果我将 const_cast 函数更改为以下内容:

template <template <bool> class W, class T>
void foo(W<true>& a, const T& t)
{
    ::foo(a, const_cast<T&>(t));
}

现在的输出是 (ideone link):

generic

这对我来说没有意义。为什么将 fooconst_cast 重载更改为调用 ::foo 会导致调用通用版本而不是 int 版本?

我对::的理解是,如果您在全局命名空间中有一个方法或一个函数,它只是为了消除调用哪个函数的歧义。 const_cast 重载仍然匹配,然后应该调用 ::foo(what<true>&, int&),它应该匹配 int 特化 - 不是吗?

此外,如果我更改顺序并在 int 专业化之后使用 ::foo 放置 const_cast 重载,则调用 int 专业化(ideone link).为什么定义的顺序在这里很重要?

只能通过依赖于参数的名称查找找到在模板之后声明的名称。仅发现 int&foo 重载是因为所涉及的类型之一 W<true> 是全局命名空间中声明的 class 模板的特化。因此,ADL 在实例化上下文中查找全局命名空间中的声明,并找到(更专门化的)所需的重载。

::foo 是一个合格的 id,它抑制了 ADL,因此只考虑在定义上下文中声明的名称。