编译器在为未定义函数选择正确的重载方面的差异

时间:2015-10-11 08:21:18

标签: c++ overloading

我们有以下代码:

//template <typename ... A>
//void foo(char a, A ... args);

template <typename T> void P(T x) { std::cout << x << ' '; }

void foo(char a) { P(3); P(a); }

template <typename ... A>
void foo(int a, A ... args)
{
    foo(args...);
    P(a);
}

template <typename ... A>
void foo(char a, A ... args)
{
    P(a);
    foo(args...);
}

int main()
{
    foo('1', '2', 48, '4', '5');
}

它在MSVC2015和ideone's GCC

上的行为有所不同

args...等于48, '4', '5'时,会调用foo。编译器的不同之处在于调用foo。 MSVC考虑了实际调用之后定义的重载(之前没有声明),而GCC仅适用于已经声明的重载。如果我取消注释声明,MSVC和GCC都会打印1 2 4 3 5 48。如果声明被注释掉,MSVC打印相同,但GCC打印1 2 3 5 52 48(52为ascii为4)

根据标准,哪种编译器是正确的?

我有n4296草案可用,但我在那里找不到答案,这份文件对我来说是不可读的......

1 个答案:

答案 0 :(得分:1)

MSVC无法为标准规定的模板实施two phase name lookup。此编译器错误地将所有名称解析延迟到模板实例化

其他编译器在模板定义时正确解析非依赖名称。这就是你观察到的差异的原因。在定义时,第二个foo模板是不可见的,因此符合标准的编译器不能使用它。但在实例化时,它是可见的,MSVC乐意找到它。