2011-10-03 6 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에서 코드를 빌드하고 실행하십시오. 출력은 다음과 같습니다. 빌드 설정에서 "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 예]

코드가 컴파일러에 잘 형성되지만 출력은 상이된다. 이 코드를 다른 플랫폼에 이식하는 것은 매우 위험합니다.

누군가이 컴파일러가 표준을 따르지 않는 배경을 가지고 있습니까?

편집 http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#197 당 2011년 10월 11일

에, 표준의 예는 잘못된 것입니다. 아래 코드를 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는 구현하지 않는 2 단계 이름 조회의 인스턴스입니다. 그리고이 경우 GCC와 Clang이 모두 정확합니다. 사실 C++ core defect report #197에서 언급했듯이 잘못된 표준입니다. C++ 11 표준에는 다른 예가 들어 있습니다.

이것은 MSVC (결코 2 단계 이름 조회를 구현하지 않음) 또는 GCC (최근까지 2 단계 이름 조회를 일률적으로 구현하지 않음)에서 Clang에 코드를 이식 할 때 표시되는 코드 중 하나입니다.

2

은 내가이 잘못된 동작입니다 당신과 함께 동의하는 것을 제외 드릴 말씀이 없습니다.

아마도 MSVC의 경우 컴파일러는 나중에 정의되지 않은 함수의 지식으로 끝내지 않는 비용으로 추가 패스를 최적화하는 것입니다. -template 호출. 나는 GCC/LLVM이 그들이하는 결과로 끝나는 방법을 얻지 못한다고 고백해야한다. 그 결과는 규칙이 아닌 예외로서 기대할 수있는 결과이다.

나는 http://bugreport.apple.com/http://connect.microsoft.com/에 버그로 신고하고 그들이 말하는 것을 보았습니까?

+0

고마워, 마흐무드. 의견이 있으면 계속 업데이트 해주세요. – Jeffrey

+1

@ 제프리 : 제 생각에 그는 당신이 버그를 제출할 것을 제안하고 있다고 생각합니다. :) –

+0

g ++ 4.6.1은 Xcode (이는 비교적 오래된 g ++ 4.2)와 동일한 동작을 나타내므로 http://gcc.gnu.org/bugzilla/에서도 버그 보고서를 제출하십시오. – zwol

5

Visual Studio에서 two-phase lookup을 구현하지 않는다는 사실에 여러분이 빠지기 쉽습니다. 템플릿을 인스턴스화 할 때 실제 이름 만 조회합니다.

그리고 Microsoft는이 시점에서 2 단계 조회를 지원하는 데 관심이 없다고 거의 결정했습니다.

+0

MSVC 잃어버린 원인이지만, gcc와 Clang이 잘못 이해하게 된 것에 놀랐습니다. –

관련 문제