为什么ADL找不到function模板?

C ++规范的哪一部分通过在关联的命名空间集合中查找函数模板来限制依赖于参数的查找? 换句话说,为什么最后的main调用不能编译?

 namespace ns { struct foo {}; template<int i> void frob(foo const&) {} void non_template(foo const&) {} } int main() { ns::foo f; non_template(f); // This is fine. frob<0>(f); // This is not. } 

这部分解释它:

C ++标准03 14.8.1.6

[注意:对于简单的函数名称,即使函数名称在调用范围内不可见,也会应用依赖于参数的查找(3.4.2)。 这是因为调用仍然具有函数调用的语法forms(3.4.1)。 但是,如果使用带有显式模板参数的函数模板,则调用不具有正确的语法forms,除非在调用点处有一个名称可见的函数模板。 如果不存在这样的名称,则调用在语法上不是格式良好的,而且依赖于参数的查找不适用。 如果某些这样的名称是可见的,则应用依赖于参数的查找,并且可以在其他名称空间中find附加的函数模板。

 namespace A { struct B { }; template<int X> void f(B); } namespace C { template<class T> void f(T t); } void g(A::B b) { f<3>(b); //ill-formed: not a function call A::f<3>(b); //well-formed C::f<3>(b); //ill-formed; argument dependent lookup // applies only to unqualified names using C::f; f<3>(b); //well-formed because C::f is visible; then // A::f is found by argument dependent lookup } 

我想细化稍微接受的答案。 OP的问题并不清楚,但标准的重要部分(Kornel引用)是这样的(重点是我的):

但是当使用具有显式模板参数的函数模板时,调用没有正确的语法forms

所以被禁止的是依靠ADL和使用显式的模板参数。 不幸的是,使用非types模板参数需要使用显式参数(除非它们具有默认值)。

下面是示例代码显示这个:

[生活]

 #include <string> #include <utility> namespace C { struct B { }; template<class T> void f(T t){} } void g(C::B b) { f(b); // OK //f<C::B>(b); // ill-formed: not a function call, but only // because explicit template argument were used std::string s; move(s); // OK //move<std::string&>(s); // Error, again because // explicit template argument were used std::move<std::string&>(s); // Ok } int main() { C::B b; g(b); } 

编辑:不,这是不对的。 见@ Kornel的答案 。


我不完全确定,但咨询了Stroustrup的“C ++编程语言”,我认为附录C第13.8.4节可能是原因。

由于frob是一个模板,所以在你调用它之后的某个点上,可以想象它将专门用于i=0 。 这意味着实现将有两种可能的方式来select要调用的函数,因为看起来它可以在实例化的位置在处理翻译单元结束时select它。

所以,我认为这个问题是你可以做的

 namespace ns { struct foo {}; template<int i> void frob(foo const&) {} } int main() { ns::foo f; frob<0>(f); return 0; } namespace ns { template<> void frob< 0 >(foo const&) { /* Do something different*/ } }