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

时间:2015-05-06 16:33:07

标签: c++ templates template-specialization overload-resolution

请考虑以下代码:

#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 )。为什么定义的顺序在这里很重要?

1 个答案:

答案 0 :(得分:4)

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

::foo是一个限定ID,用于抑制ADL,因此只考虑在定义上下文中声明的名称。