2016-07-20 4 views
2

バリデーションテンプレートを使用して、パラメータタイプをメンバ関数に格納しようとしています。私がこれを達成しようとしているのは、それぞれの型をキーに関連づけ、次にこのキーをstd :: vectorに格納することです。テンプレートパラメータパックを展開しようとするとエラーが発生する

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

その後、私はSTDにキーを格納しようとするには、次のコードを使用する::ベクトル

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...>(); 
    } 
}; 

は、私が上で立ち往生だことはあるが、次のようにこのキーを作成するためのコードがあります各クラスキーを格納するために必要なバリデーションの再帰。上記の行にエラーが表示されます。これは、パラメータパックを展開しようとする際の再帰的な手順です。私はここで間違って何をしていますか?

答えて

1

あなたが持っている:

// 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...>(); 
} 

がうまくいけば、私が追加されたコメントは、これを明確にする...あなたはN型を取る関数テンプレートにN + 1種類を取る関数テンプレートから再帰しています。基本ケースには、0種類の関数テンプレートがあります。あなたはそれを持っていません、あなたは無関係な機能を持っています - それは考慮されません。

お使いのベースケースは実際に引数なしの関数であるので、あなたのアプローチは、値にあなたのタイプを持ち上げるためにどちらかである:

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>{}...); 
} 

それともexpander trickで単一機能のすべてを実行します。

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

または、折りたたみ式のC++ 17(待機できません):

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

か、また、C++ 17で、constexprの場合(これはなし引数では動作しませんが)を持つ:

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

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

それとも一定の大手非型引数にテンプレート引数リストを乱用し、これと同様の専門化[this this](http://ideone.com/5qttEV) – WhozCraig

関連する問題