2016-07-20 3 views
2

Ich versuche variadische Vorlagen zu verwenden, um die Parametertypen für eine Elementfunktion zu speichern. Ich versuche dies zu erreichen, indem ich jeden Typ mit einem Schlüssel assoziiere und diesen Schlüssel dann in einem std :: vector ablege. Der Code für diesen Schlüssel zu schaffen ist wie folgtFehler beim Versuch, das Template-Parameterpaket zu erweitern

template <typename T> 
class ClassInfo { 
public: 
    inline static void const* GetClassKey() { 
     static char key; 
     return &key; 
    } 
}; 

Dann benutze ich den folgenden Code, um zu versuchen die Schlüssel in einem std zu speichern :: vector

class WrappedMemberFunction { 
    void *function_pointer; // Holds the member function pointer 
    void const* class_type; // Class type key 
    void const* return_type; // Return type key 
    std::vector<void const*> parameter_types; // Parameter type keys 

    void StoreArguments() {} 
    template <typename Arg, typename... Args> 
    void StoreArguments() { 
     parameter_types.push_back(ClassInfo<Arg>::GetClassKey()); 
     StoreArguments<Args...>(); // Error here: No matching member function for call to 'StoreArguments' 
    } 


public: 
    template <typename Class, typename ReturnType, typename... Args> 
    WrappedMemberFunction(ReturnType (Class::*member_pointer)(Args...)) { 
     // Store member pointer as regular old void pointer 
     function_pointer = (void*&)member_pointer; 

     // Store class type 
     class_type = ClassInfo<Class>::GetClassKey(); 

     // Store return type 
     return_type = ClassInfo<Class>::GetClassKey(); 

     // Store parameter types 
     StoreArguments<Args...>(); 
    } 
}; 

Was ich bin stecken zu werden, ist die Variadische Rekursion benötigt, um jeden Klassenschlüssel zu speichern. Ich erhalte einen Fehler in der oben angegebenen Zeile, was der rekursive Schritt beim Versuch ist, das Parameterpaket zu erweitern. Was mache ich hier falsch?

Antwort

1

Sie haben:

// function that is not a template 
void StoreArguments() {} 

// function template that takes N+1 types 
template <typename Arg, typename... Args> 
void StoreArguments() { 
    parameter_types.push_back(ClassInfo<Arg>::GetClassKey()); 

    // call function template that takes N types 
    StoreArguments<Args...>(); 
} 

Hoffentlich werden die Kommentare, die ich hinzugefügt machen dies deutlich ... Sie Rekursion aus einer Funktionsvorlage unter N + 1-Typen zu einer Funktionsvorlage unter N-Typen. Der Grundfall dort ist eine Funktionsvorlage, die 0 Typen nimmt. Sie haben das nicht, Sie haben eine Nullfunktion - die nicht berücksichtigt wird.

sind Ihre Ansätze entweder Ihre Arten in Werte zu heben, so dass Ihr Basisfall tatsächlich ist eine nullary Funktion:

template <class T> struct tag { using type = T; }; 

void StoreArgumentsImpl() { } 

template <typename Arg, typename... Tags> 
void StoreArgumentsImpl(tag<Arg>, Tags... tags) { 
    parameter_types.push_back(ClassInfo<Arg>::GetClassKey()); 

    StoreArgumentsImpl(tags...); 
} 

template <typename... Args> 
void StoreArguments() { 
    StoreArgumentsImpl(tag<Args>{}...); 
} 

Oder alles in einer einzigen Funktion mit dem expander trick:

template <typename... Args> 
void StoreArguments() { 
    using expander = int[]; 
    (void)expander{0, 
     (void(
      parameter_types.push_back(ClassInfo<Args>::GetClassKey()) 
     ), 0)... 
    }; 
} 

Oder, in C++ 17 (kann nicht warten), mit Falte Ausdrücke:

template <typename... Args> 
void StoreArguments() { 
    (parameter_types.push_back(ClassInfo<Args>::GetClassKey()), ...); 
} 

Oder auch in C++ 17, mit, wenn constexpr (obwohl dies mit keine Argumenten nicht):

template <typename Arg, typename... Args> 
void StoreArguments() { 
    parameter_types.push_back(ClassInfo<Args>::GetClassKey()); 

    if constexpr(sizeof...(Args) > 0) { 
     StoreArguments<Args...>(); 
    } 
} 
+0

oder Missbrauch nur die Vorlage Argumentliste mit einem konstanten führenden Nicht-Typ Argumente und eine ähnliche Spezialisierung, [wie diese] (http://ideone.com/5qttEV). – WhozCraig