2012-04-18 5 views
1

클래스의 멤버 함수의 서명과 실제 포인터를 템플릿 클래스의 템플릿 매개 변수로 전달하고 있습니다. 연산자 오버로드에 대해 이러한 클래스의 다른 전문화 방법이 있습니까? 나는 type_traits을 보았고 std::is_copy_assignable에서 힌트를 얻으려고했지만 g ++는 내장 (예 : __has_trivial_copy)을 사용합니다.멤버 함수가 연산자 인 경우 컴파일 타임에 확인할 수 있습니까?

+0

(a) 특정 멤버 함수 포인터가 오버로드 된 연산자이거나 (b) 예를 들어. 템플릿 인수 A는 실제로 A * A를 구현합니까? – jpalecek

+1

http://www.boost.org/doc/libs/1_49_0/libs/type_traits/doc/html/boost_typetraits/category/value_traits/operators.html – Anonymous

+0

(a). 필자는 구현이 pointer-to-member-function이 속한 유형이 점검중인 연산자를 구현하는지 확인해야한다고 생각합니다. –

답변

0

음, 나는이 질문에 대해 연구했다.

결과를 얻는 것이 가능하다고 생각하지만 클래스 A가 자체 템플릿 인수 중 하나가 클래스 B의 연산자인지 알고 싶어하기 때문에 클래스 A가 먼저 B :: 연산자가 있는지 확인해야하므로 복잡합니다. , 템플릿 인수와 같은지 확인하십시오. 이것은 신속하게 작업의 어려움을 증가시킵니다.

또한 g ++에는 고급 템플릿 사용에 대한 지원이 여전히 부족하다는 것을 테스트하는 동안 발견되었습니다. 템플릿 인수는 동일한 부재 함수 같으면 확인 예를 들어,이 코드는 2 단계, 즉이 특정 멤버 함수가 존재한다고 가정 않습니다

#include <iostream> 
using namespace std; 

struct Hello{ 
    int helloworld(){ 
     return 0; 
    } 
    int goodbyeworld(){ 
     return 0; 
    } 
}; 

template<typename T1, T1, typename T2, T2> struct is_same_method{ 
    static constexpr bool value=false; 
}; 

template<typename Return, typename Class, typename... Args, Return(Class::*member)(Args...)> 
struct is_same_method<Return(Class::*)(Args...), member, Return(Class::*)(Args...), member>{ 
    static constexpr bool value=true; 
}; 

#define method_test(a, b) is_same_method<decltype(a), a, decltype(b), b>::value 


template<typename T, T> struct what_am_I_passed; 

template<typename Return, typename Class, typename... Args, Return(Class::*member)(Args...)> 
struct what_am_I_passed<Return(Class::*)(Args...), member>{ 
    static void so_what(){ 
     /* 
     * error: ‘decltype (& Class:: helloworld)’ is not a valid type for a template constant parameter. 
     */ 
     cout<<"you passed me "<<(method_test(member, &Class::helloworld)?"helloworld":"something else")<<endl; 
    } 
}; 

int main(){ 
    what_am_I_passed<decltype(&Hello::helloworld), &Hello::helloworld>::so_what(); 
} 

지금,이 코드는 g ++ 4.4, 4.5 실패

, 4.6.1에서 충돌하고 4.6.2에서 작동합니다.

이러한 모든 문제가 발생한 후에 나는 런타임시 로직의 일부를 이식하기로 결정했습니다. 이것이 결국 내가 끝낸 것이다.

#include <iostream> 
#include <type_traits> 
using namespace std; 

template<typename mem_type, mem_type mem> struct operator_type{ 
    enum types{ 
     //complete me... 
     NONE=0, ADD, SUB, MUL, DIV, MOD, POW, UNM, EQ, NEQ, LT, LE, GT, GE, SUBSCRIPT, CALL 
    }; 
    static types what(){ return NONE; } 
}; 

typedef operator_type<int, 0>::types op_types; 

template<typename Return, typename Class, typename... Args, Return(Class::*mem)(Args...)> 
class operator_type<Return(Class::*)(Args...), mem>{ 

#define isOp(name, symbol, args)\ 
     template<typename Class_,int=0> static bool is##name(float&&){ return false; }\ 
     template<typename Class_, Return(Class_::*innermem)(Args...)=&Class_::operator symbol>\ 
     static bool is##name(int&&){ return innermem==mem && (args<0 || sizeof...(Args)==args); } 
#define testOp(name) if(is##name<Class>(0)) return op_types::name 

    //complete me... 
    isOp(ADD, +, 1) 
    isOp(SUB, -, 1) 
    isOp(MUL, *, 1) 
    isOp(DIV, /, 1) 
    isOp(MOD, %, 1) 
    isOp(POW, ^, 1) 
    isOp(UNM, -, 0) 
    isOp(EQ, ==, 1) 
    isOp(NEQ, !=, 1) 
    isOp(LT, <, 1) 
    isOp(LE, <=, 1) 
    isOp(GT, >, 1) 
    isOp(GE, >=, 1) 
    isOp(SUBSCRIPT, [], 1) 
    isOp(CALL,(), -1) 

public: 

    static op_types what(){ 
     //complete me... 
     testOp(ADD); 
     testOp(SUB); 
     testOp(MUL); 
     testOp(DIV); 
     testOp(MOD); 
     testOp(POW); 
     testOp(UNM); 
     testOp(EQ); 
     testOp(NEQ); 
     testOp(LT); 
     testOp(LE); 
     testOp(GT); 
     testOp(GE); 
     testOp(SUBSCRIPT); 
     testOp(CALL); 
     return op_types::NONE; 
    } 
}; 




template<typename T, T> struct wants_to_know_operators; 

template<typename Return, typename Class, typename... Args, Return(Class::*mem)(Args...)> 
struct wants_to_know_operators<Return(Class::*)(Args...), mem>{ 
    typedef operator_type<decltype(mem), mem> my_operator_type; 
    static void stuff(){ 
     switch(my_operator_type::what()){ 
     case op_types::NONE:  cout<<"this is not an operator"<<endl; break; 
     case op_types::CALL:  cout<<"this is operator()"<<endl; break; 
     case op_types::SUBSCRIPT: cout<<"this is operator[]"<<endl; break; 
     case op_types::SUB:   cout<<"this is operator-"<<endl; break; 
     case op_types::UNM:   cout<<"this is operator- (unary)"<<endl; break; 
     //complete me... 
     default: cout<<"something else..."<<endl; break; 
     } 
    } 
}; 

struct Test{ 
    void operator()(){ 

    } 
    Test& operator-(){ 
     return *this; 
    } 
    Test& operator-(int){ 
     return *this; 
    } 
    int operator[](int){ 
     return 0; 
    } 
    int operator[](iostream){ 
     return 0; 
    } 
    int operator==(int){ 
     return 0; 
    } 
    void f(){} 
}; 


int main(){ 
    wants_to_know_operators<decltype(&Test::f), &Test::f>::stuff(); 
    wants_to_know_operators<int(Test::*)(int), &Test::operator[]>::stuff(); 
    wants_to_know_operators<int(Test::*)(iostream), &Test::operator[]>::stuff(); 
    wants_to_know_operators<decltype(&Test::operator()), &Test::operator()>::stuff(); 
    wants_to_know_operators<decltype(&Test::operator==), &Test::operator==>::stuff(); 
    wants_to_know_operators<Test&(Test::*)(), &Test::operator- >::stuff(); 
    wants_to_know_operators<Test&(Test::*)(int), &Test::operator- >::stuff(); 
} 

구문이 다소 복잡하지만 템플릿으로 해결할 수있는 최선의 방법입니다. 동일한 운영자에 대한 다양한 과부하를 구별 할 수 있습니다. 필자의 목표는 충분하고 어쩌면 더 좋을 것이다. 왜냐하면 모든 것이 C++ 함수를 Lua로 내보내는 것이므로 물론 컴파일 타임에 Lua 스택에 푸시 할 수 없기 때문이다.

+0

그래서 당신의 코드는 컴파일러의 현재 릴리스에서 작동했지만 "여전히 매우 열악한 지원"이라고 말하고 있습니다 ... 흠, 거기에 흥미로운 기준이 있습니다. 어쩌면 이전 버전의 gcc가 C++ 11보다 우위에 있다는 뜻 일까? _had_ 미완성 된 표준에 대한 지원이 부족한가요? :) 추신 현재 릴리스에 아직 남아있는 버그를 발견 한 경우보고 한 바대로 아무도보고하지 않으면 해결되지 않습니다. –

+0

@JonathanWakely 어쩌면 나는 너무 과감하게 들렸을 것입니다. 나는 약간의 취미 프로젝트가 내 프로젝트 였음에도 불구하고 최근 버전의 g ++에서 버그 (구현이 누락 된 것이 아니라 버그)에 직면했다는 것을 의미했습니다. 또한 g ++ 4.6 또는 4.7에서 약간의 회귀 현상이 발생했기 때문에 지원은 다소 "휘발성"으로 보입니다. 이것은 완전히 이해할 수 있습니다. C++ 11은 매우 새롭고 기능은 상당히 발전했습니다. 물론, 내가 찾은 대부분의 물건을보고합니다. http://gcc.gnu.org/bugzilla/show_bug.cgi?id=52744 http://gcc.gnu.org/bugzilla/show_bug.cgi?id=53009 http://gcc.gnu.org/bugzilla를 참조하십시오. /show_bug.cgi?id=53181 –

관련 문제