使用限定类型实例化的模板内的函数的名称解析

Nik*_*mel 7 c++ templates overloading namespaces name-lookup

考虑以下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;
}
Run Code Online (Sandbox Code Playgroud)

如注释中所示,模板实例化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)’
Run Code Online (Sandbox Code Playgroud)

有人可以向我解释发生了什么事吗?我原以为它的工作方式与之相同quux<B>().它必须与foo被认为是依赖的时间有关.不幸的是我的C++ foo还不够好.当foo(int)声明不存在时,该示例编译良好,这对我来说也是令人惊讶的.

任何提示,解释和解决方法都是受欢迎的.

更新1:

我不想(读不了)移动foo(n::A)定义之前的声明quux(这将避免错误).

更新2:

感谢大卫指出相关问题模板函数调用由函数混淆与模板之前声明的错误签名.Johannes Schaub - litb接受的答案提出了一个包装类解决方案,在我的情况下也可以作为一种解决方法.但是,我并不是百分之百满意.

更新3:

我通过foo(n::A)在命名空间中定义来解决问题n.感谢Jesse Good和bames53的有用答案,不仅指出了标准的相关部分,还提供了替代解决方案.感谢大卫罗德里格斯 - 当我不理解所提出的解决方案和所有其他贡献者时,他的解释是动作的.

Jes*_*ood 2

我认为规则是14.6.4.2p1:

\n
\n

对于依赖于模板参数的函数调用,\n候选函数是使用通常的查找规则(3.4.1、\n3.4.2、3.4.3)找到的,除了:

\n

\xe2\x80\x94 对于使用非限定名称查找 (3.4.1) 或限定名称查找 (3.4.3) 的查找部分,仅\n找到来自模板定义上下文的函数声明。

\n

\xe2\x80\x94 对于使用关联命名空间 (3.4.2) 的查找部分,仅\n在模板定义上下文或模板实例化上下文中找到\n函数声明。

\n
\n

void foo(n::A) {}在模板定义上下文中不可见,因为它位于 . 之后且与 .不在同一foo命名空间中n::A。因此它需要在模板定义之前可见,或者包含在相同的命名空间中,如下所示:

\n
namespace n\n{\n    void foo(n::A) {}\n}\n
Run Code Online (Sandbox Code Playgroud)\n