2012-11-20 19 views
5

Pracuję z niektórymi funkcjami SFINAE; obecnie w części aplikacji, która musi działać w systemie Linux i Windows; wybór kompilatora to MSVC (Visual Studio 2010 10.0) dla aplikacji Windows i GCC 4.4.5 dla Linuksa.Jak ustalić, czy w klasie istnieje metoda określonego prototypu?

Muszę sprawdzić, czy dany obiekt udostępnia niektóre funkcje do przeprowadzania niestandardowej serializacji i wywoływania tych funkcji, lub wykonać prosty memcpy i sizeof(Object), podczas gdy niestandardowe metody serializacji nie są dostępne.

Problemem jest to, że kawałek kodu skompilować bez ostrzeżeń ani błędów w MSVC ale podczas kompilacji z GCC, kod jest następujący:

template 
    < 
     typename Type, 
     typename Return, 
     typename Parameter, 
     Return (Type::*Pointer)(Parameter) const 
    > struct sMemberMethodConst { }; 

template 
    < 
     typename Type, 
     typename Return, 
     typename Parameter, 
     Return (Type::*)(Parameter) 
    > struct sMemberMethod { }; 

template<typename T> struct sMemberMethodChecker 
{ 
    template <typename Type> static char HasCustomSizeMethod(sMemberMethodConst<Type, size_t, void, &Type::Size> *); 
    template <typename Type> static long HasCustomSizeMethod(...); 
    template <typename Type> static char HasSerializeMethod(sMemberMethodConst<Type, size_t, void * const, &Type::Serialize> *); 
    template <typename Type> static long HasSerializeMethod(...); 
    template <typename Type> static char HasDeserializeMethod(sMemberMethod<Type, size_t, const void * const, &Type::Deserialize> *); 
    template <typename Type> static long HasDeserializeMethod(...); 
    // Other specific method checks... 

    enum 
    { 
     HAS_CUSTOM_SIZE_METHOD = (sizeof(HasCustomSizeMethod<T>(0)) == sizeof(char)), 
     HAS_SERIALIZE_METHOD =  (sizeof(HasSerializeMethod<T>(0)) == sizeof(char)), 
     HAS_DESERIALIZE_METHOD = (sizeof(HasDeserializeMethod<T>(0)) == sizeof(char)), 
     IS_CUSTOM =     HAS_CUSTOM_SIZE_METHOD && 
            HAS_SERIALIZE_METHOD && 
            HAS_DESERIALIZE_METHOD, 
     // Other 'shortcuts'... 
    }; 

i błąd, że mam coraz podczas kompilacji z GCC jest:

invalid parameter type 'void' in declaration template<class Type, class Return, class Parameter, Return (Type::* Pointer)(Parameter)const>

w pierwszym wierszu struct sMemberMethodChecker. Jestem całkiem pewien, że nie brakuje mi słów, ale nie rozumiem, dlaczego dostaję błąd i nie rozumiem błędu.

Wiem, że MSVC jest luźny ze standardem podczas GCC jest zgodny ze standardem całkiem dobrze, więc zastanawiam się, czy problem leży w bok MSVC który pozwala kodu głupie!

Oto pytania:

  • Dlaczego otrzymuję błąd invalid parameter type 'void' w struct sMemberMethodChecker?.
  • Dlaczego kod jest poprawny w MSVC, ale jest nieprawidłowy w GCC ?.
  • Czy ten kod jest niestandardowy ?.
  • Czy sztuczka SFINAE nie zawiera C++ 11?
+0

Czy "const void * const" jest dozwolone? Mówisz kompilatorowi, że masz obiekt typu "const void". Ale pustki nie mogą być modyfikowane tak czy inaczej AFAIK? Co się stanie, jeśli spróbujesz 'void * const'? – RedX

+3

Dobre pytanie. Wydaje się, że GCC nie akceptuje 'szablon < TypeName typ, TypeName powrót, TypeName parametr Return (Typ :: *) (void **' ** ') > struct sMemberMethod {};' jako parametr . Podczas gdy MSVC jest o tym liberalny. – iammilind

+1

Uważam, że iammilind ma rację. W przeciwieństwie do C, C++ nie zezwala na 'void' na liście argumentów funkcji. Dzieje się tak, ponieważ w C 'f()' jest funkcją bez prototypu (= parametry nieokreślone), natomiast w C++ 'f()' jest funkcją bez żadnych argumentów. – Angew

Odpowiedz

2

Dlaczego dostaję nieprawidłowy typ parametru „void” błąd w struktury sMemberMethodChecker ?.

Dlaczego kod jest prawidłowy w MSVC, ale nie znajduje się w GCC ?.

wierzę, że MSVC jest bycie pomocny jednak GCC jest bycie rygorystyczne w tym konkretnym kodzie. Jak to w jakiś sposób nie pozwala Return (Type::*)(void). Jednak trzeba go jeszcze bardziej przekopać, aby poznać dokładny powód.

Czy ten kod nie jest standardem ?.

Nie można powiedzieć, dopóki nie zostanie skompilowany. A wyszukiwanie standardu dla funkcji takich jak SFINAE nie jest dla wszystkich filiżanką herbaty.

Czy sztuczka SFINAE nie zawiera C++ 11?

Wcale nie. SFINAE istniało przed C++ 11.
Oto uproszczone sposób, co chcesz zrobić:

template<typename ClassName, typename ClassMethodType> 
struct HasMethod 
{ 
    template<typename Type, Type Object> struct Contains; 
    typedef char (&yes)[2]; 

    template<typename Class, typename MethodType> 
    static yes Check (Contains<MethodType, &Class::size>*); 
    template<typename Class, typename MethodType> 
    static char Check (...); 

    static const bool value = (sizeof(Check<ClassName,ClassMethodType>(0)) == sizeof(char)); 
}; 

HasMethod<ClassName, ClassMethodType>::value daje odpowiedź, jeśli wewnątrz niego pewna metoda członek typ istnieje, czy nie.
Do tej pory HasMethod<> jest zastrzeżona dla metody o nazwiesize z typem podanym przez użytkownika. Możesz jednak utworzyć makro dla powyższego kodu i ustawić nazwę funkcji konfigurowalną na.

Oto working demo with g++.

+1

Bardzo dobre odpowiedzi! niestety przykładowy kod nie pasuje dokładnie do tego, czego potrzebuję, ale podpowiedział mi, aby rozwiązać główny problem całkiem dobrze, btw: dzięki za poprawienie mojego słabego angielskiego;) –

Powiązane problemy