2011-01-13 4 views
12

내가 코드를 컴파일했을 때이 발생한다고 생각했지만 그렇지 않습니다. 그래서 여기에있는 지역 표준 전문가 중 일부가 도움을 줄 수 있기를 바랍니다 .-). 여기에 무슨 일이 일어나고 있는지 설명하기 위해, 그래서잠재적 인 g ++ 템플릿 버그?

#include <iostream> 

template <class T = int> 
class A { 
public: 
    class U { 
    }; 

public: 
    U f() const { return U(); } 
}; 

// test either the work around or the code I want... 
#ifndef USE_FIX 
template <class T> 
bool operator==(const typename A<T>::U &x, int y) { 
    return true; 
} 
#else 
typedef A<int> AI; 
bool operator==(const AI::U &x, int y) { 
    return true; 
} 
#endif 

int main() { 
    A<int> a; 
    std::cout << (a.f() == 1) << std::endl; 
} 

:

나는 기본적으로이 유사한 몇 가지 코드가 있습니다. 클래스 (A) 내부 클래스 (U) 및 해당 내부 클래스 (f()) 인스턴스를 반환 할 수있는 하나 이상의 멤버 함수가있는 템플릿이 있습니다.

그런 다음이 내부 형식을 다른 형식 (이 경우 int)과 비교하는 operator== 함수를 만들려고합니다. 그러나이 형식은 중요하지 않습니다.

USE_FIX하지 나는 다음과 같은 오류 얻을 정의 : 그냥 경우 사실, 내가 분명히이기 때문에, 이상하게 보인다

test.cc: In function 'int main()': 
test.cc:27:25: error: no match for 'operator==' in 'a.A<T>::f [with T = int]() == 1' 

(나는 생각한다)는 템플릿 operator== 규정이 포함되어야 컴파일러 (USE_FIX 사용)에 대한 약간의 작업을 수행하면 더 이상 오류가 발생하지 않습니다. 불행히도 "수정"은 일반적으로 템플릿의 특정 인스턴스에 대해서만 작동하지 않습니다.

예상대로 작동하나요? 아니면 단순히 허용되지 않습니까?

BTW : 문제가 있다면 gcc 4.5.2를 사용하고 있습니다.

+1

단순히 허용되지 않습니다. 문제에 대해 더 많이 알고 있다면 적절한 재 설계를 제안 할 수 있습니다. –

+0

+1 좋은 질문입니다. :-) – Nawaz

+0

가능한 [C++ 템플릿의 메소드 유형에서 클래스 유형을 추론하는 방법] (http://stackoverflow.com/questions/3830491/how-to-deduce-class-type-from-method-type- in-c-templates) –

답변

15

const typename A<T>::U &x의 문제점은 U이 종속 형식이고 컴파일러가 인수 ()를 추론 할 수 없다는 것입니다 (이것은 비 감손 된 컨텍스트 중 하나입니다). 그런 다음 호출 할 경우

class X { }; 
class Y { }; 
class Z { }; 

template <> class A<X> { 
public: 
    typedef Z U; 
}; 

template <> class A<Y> { 
public: 
    typedef Z U; 
}; 

:

Z a; 
a == 1; 

어떤 컴파일러로 T을 추론한다

당신은, 예를 들어, A의 두 전문을 가질 수있다? X? Y? 을 추론하는 것이 허용 (또는 때때로 가능) 아니다,

template <class T = int> 
class A { 
public: 
    class U { 
    }; 

    friend bool operator==(const U& x, int y) { 
     return true; 
    } 

public: 
    U f() const { return U(); } 
}; 
+0

+1 좋은 질문에 대한 좋은 답변! – Nawaz

+0

@James : 그런데'Z'는 클래스 템플릿 안에서 선언되어야합니다. 그러면 그의 상황과 예제가 함께 맞을 것입니다. 너 무슨 소리 야? 제 말은,'Z'는'A'와는 독립적 인 반면,'U'는 의존형이라는 것입니다. – Nawaz

+3

@Nawaz :'Z'가 종속적인지 여부는 중요하지 않습니다; 'U'가 의존적이라는 것이 중요합니다. 'Z'는 무엇이든 될 수 있습니다. (원래'int'를 사용 했었습니다. 그러나 내장형 연산자로 인해 과부하 해결 중에 함수 템플릿이 고려되지 않았기 때문에 잘못되었습니다. 따라서 연산자'nottemplate overload가없는 형식으로'Z'를 도입했습니다 =='). –

11
template <class T> 
bool operator==(const typename A<T>::U &x, int y) { 
    return true; 
} 

이 템플릿을 사용하여이 특정한 경우에

하나의 해결책은 클래스 템플릿의 내부 nontemplate 친구로 operator==을 선언하는 것입니다 템플릿 매개 변수 Tx 유형입니다. 그것은 비 추론 할 수없는 맥락으로 알려져 있습니다. (다른 매개 변수 A를 전문으로 할 수 일예로 누군가가, double을 말하고 A<int>::U에 대한 A<double>::U 타입 정의를 확인하십시오.)

해결 방법이 없습니다, 당신은 명시 적으로 operator==에 대한 추악한 구문하게 템플릿 매개 변수를 지정해야합니다.

+1

나는이 설명이 James의 설명보다 낫다고 생각한다. 간결하고 정확한. +1 – Nawaz

4

오히려 분명한 이유는 허용되지 않습니다. 일반적으로 컴파일러가 연산자 ==에 대한 호출에서 템플릿 인수를 추론 할 수있는 방법이 없습니다. 분명히 중첩 된 유형 U은 묶는 A 전문화를 고유하게 정의한다고 가정했습니다. 즉, 컴파일러가 템플릿 인수 T을 추론 할 수없는 형태 A<int>::U의 인수 운영자 ==을 템플릿 호출 할 경우,이 경우 A

template <> class A<int> { 
public: 
    class U {}; 
}; 

template <> class A<double> { 
public: 
    typedef A<int>::U U; 
}; 

두 명시 적 전문으로 다음의 예에 의해 설명 될 수있는 사실이 아닙니다 템플릿 연산자 ==. Tint 또는 double이되어야합니까? 말할 길이 없어요.

이러한 모호성을 피하기 위해 이러한 상황을 추론하지 않은 컨텍스트이라고합니다. 중첩 된 클래스 템플릿 변수를 중첩 된 형식에서 제외하는 것은 추론되지 않은 컨텍스트의 예입니다.

+0

+1 좋은 질문에 좋은 답변입니다! – Nawaz

관련 문제