2014-12-08 4 views
2

CRTP를 사용하여 클래스에 함수의 템플릿 인수 종속 추가를 제공합니다 (이 경우 템플릿 클래스 ImplAdd을 사용하여 operator +operator +=이 추가됨). 실제로 ImplAdd에서 상속 클래스 상수 값을 정의하기 때문에클래스 내 선언 된 프렌드 연산자의 lefthand 인수의 암시 적 변환

template<class Type, bool active> 
struct ImplAdd{ 
    virtual int get_val_() const = 0; 
    virtual void set_val_(int) = 0; 
}; 

//if activated is true, the operators + and += will be defined 
template<class Type> 
class ImplAdd < Type, true > { 
    virtual int get_val_() const = 0; 
    virtual void set_val_(int) = 0; 
    Type* this_(){ return (Type*)this; } 
public: 
    Type& operator +=(const Type& x){ 
     set_val_(get_val_() + x.get_val_()); 
     return *this_(); 
    } 

    //This should enable conversions on the lefthand argument 
    friend Type& operator+(const Type& lhs, const Type& rhs){ 
     Type ret = lhs; 
     return ret += rhs; 
    } 
}; 

이 필요하고 : 이전의 경우, 암시 적 변환 내가이 같은 수준의 친구 연산자를 사용하는 것을 의미하는 두 인수에 수행해야 범위가 지정된 열거 형과 마찬가지로 해당 상수의 고유 한 값 유형입니다.

//by using true as the template argument, the operators + and += will be defined 
class MyEnum : public ImplAdd<MyEnum, true>{ 
    int get_val_() const override{ 
     return (int)value; 
    } 
    void set_val_(int v) override{ 
     value = (ValueT)v; 
    } 
public: 
    enum class ValueT{ 
     zero, one, two 
    }; 
private: 
    typedef int UnderlyingT; 
    ValueT value; 
public: 
    static const ValueT zero = ValueT::zero; 
    static const ValueT one = ValueT::one; 
    static const ValueT two = ValueT::two; 
    MyEnum(ValueT x) : value(x){} 
    MyEnum(const MyEnum& other) : value(other.value){} 
}; 

제 생각에 다음 코드는 쉽게 컴파일해야하지만 그렇지 않습니다. 두 라인에 대한

int main(int argc, char* argv[]) 
{ 
    MyEnum my = MyEnum::zero;    //works 
    my += MyEnum::one;      //works 
    my = MyEnum(MyEnum::zero) + MyEnum::two; //works 
    my = MyEnum::zero + MyEnum(MyEnum::two); //ERROR C2676 
    my = MyEnum::zero + MyEnum::two;   //ERROR C2676 
    MyEnum my2 = my + my;     //works 
    return 0; 
} 

는 C2676 표시, 다음과 같은 오류 메시지가 인쇄되어 있습니다 : 내가 잘못 뭐하는 거지

error C2676: binary '+' : 'const MyEnum::ValueT' does not define this operator or a conversion to a type acceptable to the predefined operator 

? 두 인수에서 암시 적 변환을 가능하게하는 일반적인 방법으로 연산자를 클래스 친구로 정의하는 것을 사용하지 않습니까? 그렇지 않은 경우이 경우 어떻게해야합니까?

+0

관련/중복 : http://stackoverflow.com/q/27281500 – dyp

답변

3

§13.3.1.2 [over.match.oper]/P3 (강조 추가)

타입의 왼쪽 피연산자 이진 연산자 @위한

CV-비정규 버전 T1이며 부재 후보, 비회원 후보내장 후보이다 지정된 CV-비정규 버전 T2 후보 함수 세 세트 인 유형의 오른쪽 피연산자 구성 다음과 같이

  • [...]
  • 비 부재 후보들의 세트 에 이름 조회에 대한 일반적인 규칙에 따른 표현의 맥락에서 [email protected]의 비정규 조회의 결과 모든 멤버 함수가 무시된다는 점을 제외하고는 부적합 함수 호출 (3.4.2) . 오퍼랜드 은 클래스 타입이 없다면 T1이 열거되면 그러나 룩업들만 비 멤버 함수 "(아마도 CV 수식) T1을 참조하여"제 1 타입 T1의 파라미터 또는이 세트 ( 오른쪽 피연산자가있는 경우) T2 또는 " (가능하면 CV 자격이 있음) T2에 대한 참조"의 두 번째 매개 변수는 T2이 열거 형일 때 후보 함수입니다. 도 피연산자는 클래스 유형이있는 경우

  • [...]
  • 은 더 분명 영어로, 당신은 과부하가 인 고려하는 열거 피연산자에 정확히 일치하는이 필요합니다 왜 my = MyEnum::zero + MyEnum::two;가 작동하지 않습니다. 괴상하게도 my = MyEnum::zero + MyEnum(MyEnum::two);은 GCC에서 컴파일되지만 Clang에서는 컴파일되지 않습니다.내가 합법적이 아닌 것을 발견 할 수 없으므로, 이것이 컴파일러 버그일지도 모른다.

    +0

    이것이 올바르게 작동하지 않는 이유에 대한 올바른 대답이지만 가능한 해결책은 무엇인지 생각해보십시오. – iFreilicht