我在Xcode 4.1和Visual Studio 2008上测试c ++标准ISO / IEC 14882-03 14.6.1 / 9中的代码。两个编译器的输出都与标准的预期结果不同。
代码粘贴在下面。
#include <stdio.h>
#include <iostream>
using namespace std;
void f(char);
template <class T > void g(T t)
{
f(1);
f(T(1));
f(t);
}
void f(int);
void h()
{
g(2);
g('a');
}
void f(int)
{
cout << "f int" << endl;
}
void f(char)
{
cout << "f char" << endl;
}
int main() {
h();
return 0;
}
作为标准的描述。预期的输出应该是
f char
f int
f int
f char
f char
f char
在Xcode 4.1上构建并运行代码。输出如下。在构建设置中,我尝试将“Compiler for C / C ++ / Object-C”更改为Apple LLVM Compiler 2.1,Gcc 4.2和LLVM GCC 4.2。输出是相同的。
f char
f char
f char
f char
f char
f char
在Microsoft Visual Studio 2008上构建并运行代码。输出如下。
f int
f int
f int
f int
f char
f char
标准的说明(14.6.1 / 9)粘贴在下面。
如果名称不依赖于模板参数(如14.6.2中所定义),则该名称的声明(或声明集)应在名称出现在模板中的范围内定义;该名称绑定到此时发现的声明(或声明),并且此绑定不受在实例化时可见的声明的影响。 [实施例:
void f(char);
template<class T> void g(T t)
{
f(1); // f(char)
f(T(1)); // dependent
f(t); // dependent
dd++; // not dependent
}
void f(int);
double dd;
void h()
{
// error: declaration for dd not found
g(2); // will cause one call of f(char) followed // by two calls of f(int)
g(’a’); // will cause three calls of f(char)
-end example]
编码器编写良好,但输出结果不同。将此代码移植到不同的平台是非常危险的。
有人知道这些编译器不符合标准的背景吗?
2011年10月11日编辑
Per http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#197,标准中的示例是错误的。我在Clang和Gcc上测试下面的代码。
#include <stdio.h>
#include <iostream>
using namespace std;
void f(char);
template <class T > void g(T t)
{
f(1);
f(T(1));
f(t);
}
enum E{ e };
void f(E );
void h()
{
g(e);
g('a');
}
void f(E )
{
cout << "f E" << endl;
}
void f(char)
{
cout << "f char" << endl;
}
int main() {
h();
return 0;
}
预期输出。
f char
f E
f E
f char
f char
f char
谢谢,
杰弗里
答案 0 :(得分:5)
您遇到的是Visual Studio未实现two-phase lookup的事实。它们仅在您实例化模板时查找实际名称。
微软在这一点上几乎已经决定他们对支持两阶段查找不感兴趣。
答案 1 :(得分:3)
如第一个例子所述,这是一个两阶段名称查找的实例,GCC和Clang都实现了,但MSVC却没有。在这种情况下,GCC和Clang都是正确的:它实际上是错误的标准,如C ++ core defect report #197中所述。 C ++ 11标准包含一个不同的例子。
这是我们在从MSVC(从未实现过两阶段名称查找)或从GCC(直到最近才统一实现两阶段名称)的代码移植到Clang时看到的most common problems之一)。
答案 2 :(得分:2)
我不知道该告诉你什么,除非我同意你这是不正确的行为。
我认为可能发生的事情是,在MSVC的情况下,编译器正在优化一次额外的传递,代价是最后定义的函数的知识,在非non的情况下不应该使用模板调用。我必须承认,我不知道GCC / LLVM最终会得到他们所做的结果,因为结果是你所期望的异常,而不是规则。
我想我会将其归档为http://bugreport.apple.com/和http://connect.microsoft.com/上的错误,看看他们说了什么?