考虑以下C代码示例:
namespace n { struct A {}; } struct B {}; void foo(int) {} template<typename T> void quux() { foo(T()); } void foo(n::A) {} void foo(B) {} int main() { quux<n::A>(); // Error (but works if you comment out the foo(int) declaration) quux<B>(); // Works return 0; }@H_403_4@如注释中所示,模板实例化quux< n :: A>()会导致编译器错误(在GCC 4.6.3上):
foo.cpp: In function ‘void quux() [with T = n::A]’: foo.cpp:22:16: instantiated from here foo.cpp:13:5: error: cannot convert ‘n::A’ to ‘int’ for argument ‘1’ to ‘void foo(int)’@H_403_4@有人可以向我解释发生了什么事吗?我希望它与quux< B>()的工作方式相同.当foo被认为是依赖时,它必须与某些事情有关.不幸的是我的C foo不够好.当foo(int)声明不存在时,该示例编译正常,这对我来说也是令人惊讶的. @H_403_4@任何提示,解释和解决方法都是受欢迎的. @H_403_4@更新1: @H_403_4@我不想(读不了)在quux的定义之前移动foo(n :: A)的声明(这将避免错误). @H_403_4@更新2: @H_403_4@感谢David指出相关问题Template function call confused by function with wrong signature declared before template.Johannes Schaub – litb接受的答案提出了一个包装类解决方案,在我的情况下也可以作为一种解决方法.但是,我并不是百分之百满意. @H_403_4@更新3: @H_403_4@我通过将foo(n :: A)的定义放在命名空间n中解决了这个问题.感谢Jesse Good和bames53的有用答案,不仅指出了标准的相关部分,还提供了替代解决方案.感谢大卫罗德里格斯 – 当我不理解所提议的解决方案和所有其他贡献者时,他的解释.
解决方法
我认为规则是14.6.4.2p1:
@H_403_4@For a function call that depends on a template parameter,the@H_403_4@void foo(n :: A){}在模板定义上下文中不可见,因为它位于后面且foo与n :: A不在同一名称空间中.所以它需要在模板定义之前可见,或者包含在同一名称空间中,如下所示:
candidate functions are found using the usual lookup rules (3.4.1,
3.4.2,3.4.3) except that: @H_403_4@— For the part of the lookup using unqualified name lookup (3.4.1) or qualified name lookup (3.4.3),only
function declarations from the template definition context are found. @H_403_4@— For the part of the lookup using associated namespaces (3.4.2),only
function declarations found in either the template definition context
or the template instantiation context are found.
namespace n { void foo(n::A) {} }