第二个void foo(...
是重载(而不是特化),它在定义中不可见,foo_fun::fun
因此不会在模板定义的上下文中找到。因为T*
是依赖类型,foo
表达式中的解析foo((T*)0, 0)
将延迟到模板实例化时间,并且实例化的上下文也将被考虑。但是,标准的 14.6.4.2 规定,如果函数名称是非限定 ID而不是模板 ID,则对于非 ADL 查找,仅考虑在模板定义点可见的函数。命名空间中没有函数参数,Foo
因此不会发生依赖于参数的查找,因此模板版本foo
被调用而不是非模板重载。
非常感谢 litb 对此答案的更正。
如果您将其设为如下特化,则由于在模板实例化时选择了特化,因此只要相关特化在函数模板第一次实例化时可见,就可以调用特化int
。
namespace Foo {
template<>
void foo<int>(int *, int) { puts("int"); }
}
当前标准的第 14 章,但可读性不强:)
Edit: If I had to pick the most relevant part of the standard it would probably be 14.6 [temp.res] para 9. (Slightly abbreviated) If a name does not depend on a template-parameter, a declaration for that name shall be in scope at the point at where the name appears in the template definition; the name is bound to the declaration found at that point and this binding is not affected by declarations that are visible at the point of instantiation.
Edit, edit: But you also need to take into account 14.6.4.2 [temp.dep.candidate]. It is very difficult and dangerous to try and reference the standard because of all the interdependencies, this answer is a case in point.