2011-10-03 55 views
14

我测试了Xcode 4.1和Visual Studio 2008上的C++标准ISO/IEC 14882-03 14.6.1/9中的代码。这两种编译器都与标准的预期结果不同。类模板中名称解析的实际结果与C++ 03标准不同

代码粘贴在下面。

#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上的代码。输出如下。在构建设置中,我尝试将“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) 

末端示例]

的代码是公形成到编译器,但输出是不同的。将此代码移植到不同的平台上将是非常危险的。

有人有背景为什么这些编译器不遵循标准?

编辑于2011-11-10

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 

感谢,

杰弗里

+2

+1对于第一个问题 –

+0

有趣的是,Clang 2.9与gcc有相同的问题。 –

回答

3

正如第一个例子所述,这是一个两阶段名称查找的实例,GCC和Clang都实现了它,但MSVC并没有实现。在这种情况下,GCC和Clang都是正确的:它实际上是错误的标准,正如C++ core defect report #197所述。 C++ 11标准包含一个不同的例子。

这是我们在从MSVC(从未实现两阶段名称查找)或从GCC(直到最近才统一实施两阶段名称查找)将代码移植到Clang时看到的most common problems之一。

2

我不知道该怎么告诉你,只是我同意你的观点,这是不正确的行为。

我认为可能发生的情况是,在MSVC的情况下,编译器正在优化掉一个额外的通道,代价是结束后面定义的函数的知识,而这些函数不应该用于非模板调用。我必须承认,我不明白GCC/LLVM如何最终取得他们所做的结果,因为结果是你所期望的例外而非规则。

我想我会把它作为一个错误http://bugreport.apple.com/http://connect.microsoft.com/,看看他们说什么?

+0

谢谢,马哈茂德。如果有任何评论,请让我更新。 – Jeffrey

+1

@杰弗里:我想他是在暗示你提交了这个bug。 :) –

+0

g ++ 4.6.1表现出与Xcode(它有相对古老的g ++ 4.2)相同的行为,所以请在http://gcc.gnu.org/bugzilla/上提交错误报告。 – zwol

5

您遇到的情况是Visual Studio没有实现two-phase lookup。他们只在实例化模板时查找实际名称。

而且微软已经决定在这一点上他们不想支持两阶段查找。

+0

MSVC是一个失败的原因,但我很惊讶,海湾合作委员会和Clang会弄错它。 –

相关问题