2012-11-20 5 views
5

Ich arbeite mit einigen SFINAE-Funktionen; derzeit in einem Teil einer Anwendung, die in Linux und Windows ausgeführt werden muss; Die Compiler-Optionen sind MSVC (Visual Studio 2010 10.0) für Windows-Anwendungen und GCC 4.4.5 für die Linux-Anwendungen.Wie kann man herausfinden, ob eine Methode eines bestimmten Prototyps in einer Klasse existiert?

Ich muss überprüfen, ob ein bestimmtes Objekt einige Funktionen bietet, um eine benutzerdefinierte Serialisierung durchzuführen und diese Funktionen aufzurufen, oder eine einfache memcpy und sizeof(Object) ausführen, während die benutzerdefinierten Serialisierungsmethoden nicht bereitgestellt werden.

Das Problem ist, dass ein Stück Code ohne Warnungen noch Fehler in MSVC kompilieren, aber während mit GCC kompilieren, der Code ist folgende:

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'... 
    }; 

Und die Fehler, die ich bekommen habe, während sie mit GCC kompilieren ist:

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

in der ersten Zeile der struct sMemberMethodChecker. Ich bin mir ziemlich sicher, dass ich weder typename noch Wörter verlege, aber ich verstehe nicht, warum ich den Fehler bekomme und den Fehler nicht verstehe.

Ich weiß, dass die MSVC ist locker mit Standard während GCC entspricht dem Standard ziemlich gut, also frage ich mich, ob das Problem liegt in der MSVC Seite, die dummer Code ermöglicht!

Hier sind die Fragen:

  • Warum erhalte ich die invalid parameter type 'void' Fehler in der struct sMemberMethodChecker?.
  • Warum ist der Code in MSVC gültig, aber in GCC ungültig ?.
  • Ist dieser Code nicht Standard ?.
  • Ist die SFINAE-Tricky ausschließlich C++ 11?
+0

Ist 'const void * const' erlaubt? Sie sagen dem Compiler, dass Sie einen Objekttyp "const void" haben. Aber Voids können sowieso nicht geändert werden AFAIK? Was passiert, wenn Sie 'void * const' versuchen? – RedX

+3

Gute Frage. Es scheint, dass GCC nicht 'Vorlage akzeptieren < Typname Typ, Typname Return, Typname Parameter, Return (Typ :: *) (' ** ungültig ** ') > struct sMemberMethod {};' als Parameter . MSVC ist dagegen liberal. – iammilind

+1

Ich glaube, iammilind hat Recht. Im Gegensatz zu C lässt C++ in der Argumentliste einer Funktion nicht "void" zu. Das liegt daran, dass 'f()' in C eine Funktion ohne Prototyp ist (= Parameter nicht spezifiziert), während in C++ 'f()' eine Funktion ohne Argumente ist. – Angew

Antwort

2

Warum erhalte ich den ungültigen Parameter Typ 'ungültig' Fehler in der Struktur sMemberMethodChecker ?.

Warum ist der Code in MSVC gültig, aber nicht in GCC ?.

Ich glaube, dass MSVC hilfreich ist, aber GCC wird in diesem bestimmten Code streng sein. Da es irgendwie nicht erlaubt Return (Type::*)(void). Allerdings muss man es genauer auskundschaften, um den genauen Grund zu erfahren.

Ist dieser Code kein Standard ?.

Kann nicht sagen, bis es nicht kompiliert. Und die Suche nach Standards wie SFINAE ist nicht jedermanns Sache.

Ist die SFINAE-Tricky ausschließlich C++ 11?

Überhaupt nicht. SFINAE existierte vor C++ 11.
Hier ist die vereinfachte Art und Weise von dem, was Sie tun möchten: Wenn eine bestimmte Typ Element Methode innerhalb es existiert oder nicht

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 Ihr gibt die Antwort.
Ab sofort HasMethod<> ist exklusiv für die Methode Namensgebungsize mit vom Benutzer bereitgestellten Typ. Sie können jedoch ein Makro für den obigen Code erstellen und den Funktionsnamen konfigurierbar machen.

Hier ist ein .

+1

Sehr gute Antworten! Leider passt der Beispielcode nicht genau zu dem, was ich brauche, sondern hat mich dazu gebracht, das Hauptproblem ziemlich gut zu lösen, btw: Danke für die Korrektur meines schlechten Englisch;) –