2011-10-03 54 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會弄錯它。 –