请考虑以下代码:
#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
这对我没有意义。为什么更改const_cast
的{{1}}重载以调用foo
会导致调用泛型版本而不是int版本?
我对::foo
的理解是,在全局命名空间中有方法或函数的情况下,只需要消除要调用的函数的歧义。 ::
重载仍然匹配,然后调用const_cast
,它应该与::foo(what<true>&, int&)
专精相匹配 - 不应该吗?
此外,如果我在int
专精化后使用const_cast
更改订单并放置::foo
重载,则会调用int
专精(ideone link )。为什么定义的顺序在这里很重要?
答案 0 :(得分:4)
模板后声明的名称只能通过参数依赖名称查找找到。您只能找到foo
int&
的重载,因为其中一个类型W<true>
是全局命名空间中声明的类模板的特化。因此,ADL在实例化上下文中查找全局命名空间中的声明,并找到(更专业的)所需的重载。
::foo
是一个限定ID,用于抑制ADL,因此只考虑在定义上下文中声明的名称。