2

私は、C++で拡張可能な小さなスクリプトインタープリタを作成しようとしています。そのために、関数ハンドラはディスパッチテーブルに挿入されます。 私の質問にsimplyfyするには、handlertypeは、次のように定義された(実際のコードでは、これは引数リストのパラメータが含まれており、戻り値の型):template-template-parameter deducationがテンプレートメソッドで失敗しました(明示的には特化されていますが)

// Handler type 
using function_type = void(int); 

ディスパッチテーブルは、今のところ、簡単な順不同のマップであり、キーとして(一種の)マングルされた名前を持つオーバーロードを実装する:

// Dispatch table 
std::unordered_map<std::string, function_type*> fn_handlers; 

方法は、この表に追加され、直接などのいずれかタイプintの二つの引数を取る簡単な方法(operator+iiは、私の場合には、このためにうまく管理名前です)のように:

fn_handlers["operator+ii"] = my_add_handler; 

しかし、多くのハンドラ、基本的な数学に関連し、特にものは、引数の様々なを受け入れますか、 intdoubleのすべての組み合わせが有効で、4つのメソッドと4つのディスパッチテーブルのエントリが生成されます。したがって、私はテンプレートを使ってこれらのメソッドを実装することに決めました。例を与えることを 、これは基本的に、この(再simplyfied)されることがあります。

template<class A, class B> 
void my_add_handler(int /* simplified... */) 
{ 
    // Something here A and B are needed 
} 

ディスパッチテーブルは、このように満たされている:

fn_handlers["operator+ii"] = my_add_handler<int,int>; 
fn_handlers["operator+di"] = my_add_handler<double,int>; 
fn_handlers["operator+id"] = my_add_handler<int,double>; 
fn_handlers["operator+dd"] = my_add_handler<double,double>; 

まだ入力することがたくさんあるが、これは大丈夫です今。テンプレートパラメータとメソッドのシグネチャ(マングル名)との間には相関関係が明らかにありとにかく以来、私はあなたが書くことができること、これを自動化しようとした(パラメータ名mangelingはhandler_provider内で行われることになる::追加):

handler_provider<int, int>::add<my_add_handler>("operator+"); 
handler_provider<double, int>::add<fn_add_handler>("operator+"); 
handler_provider<int, double>::add<fn_add_handler>("operator+"); 
handler_provider<double, double>::add<fn_add_handler>("operator+"); 

最初は引数を取り、それを第2の型のテンプレート引数として取ります(したがって、<int, int>部分を2回タイプする必要はありません)。

説明のためだけです。

handler_provider<int, int>::add<my_add_handler<int,int>>("test"); 

をしかし、それはまさに私が(<int,int>をtwict)を省略したい、この重複です:私は明示的にこのようmy_add_handlerテンプレートを専門になり、私の承知しています。

しかし、私は最後の部分でエラーが発生し続けます。以下のようhandler_provider::add方法は、(それはここでのポイントはなく、として期待動作するため、上述したようmangelingパラメータ名が省略されている)に定義される:

template<class... Ts> 
struct handler_provider 
{ 
    // Overload for templates, such as 'test_handler' 
    template<template<class...> class F> 
    static void add(const std::string name) 
    { 
    handler_provider<Ts...>::add<F<Ts...>>(name); 
    } 

    // Overload for non-template (or already specialized) handlers (aka. function pointers) 
    template<function_type F> 
    static void add(const std::string name) 
    { 
    fn_handlers[name] = F; 
    } 
}; 

最初の過負荷が、前記のように、正確なためと考えられます前述のケースでは、以下のハンドラはテンプレート以外の関数と完全に特殊化された関数をインストールします。

しかし、これは私に、上記のような呼び出しから内部テンプレートが推定できないことを伝えます。私は私が完了し、私は全く何を推測するコンパイラを告げたことを考えていなかったコール(再び)にテンプレート引数を専門:外可変長引数テンプレートclass... Tsため

handler_provider<int, int>::add<my_add_handler>("operator+"); 

引数は、明示的に<int, int>の名前とシンプルされています内部のテンプレートテンプレートの引数はmy_add_handlerという名前です。しかし、コンパイラはこれを無視しているようです(?)。これは私が得る出力(GCC 5.4.0 -std=c++14を使用して)です:私は2番目のエラーを取得し

$ g++ -std=c++14 sci_e1.cpp -o sci 
sci_e1.cpp: In function ‘int main()’: 
sci_e1.cpp:45:55: error: no matching function for call to ‘handler_provider<int, int>::add(const char [5])’ 
    handler_provider<int, int>::add<my_add_handler>("operator+"); 
                  ^
sci_e1.cpp:17:15: note: candidate: template<template<class ...> class typedef F F> static void handler_provider<Ts>::add(std::__cxx11::string) [with F = F; Ts = {int, int}] 
    static void add(const std::string name) 
      ^
sci_e1.cpp:17:15: note: template argument deduction/substitution failed: 
sci_e1.cpp:24:15: note: candidate: template<void (* F)(int)> static void handler_provider<Ts>::add(std::__cxx11::string) [with void (* F)(int) = F; Ts = {int, int}] 
    static void add(const std::string name) 
      ^
sci_e1.cpp:24:15: note: template argument deduction/substitution failed: 
sci_e1.cpp:45:55: error: could not convert template argument ‘my_add_handler’ to ‘void (*)(int)’ 
    handler_provider<int, int>::add<my_add_handler>("operator+"); 
                  ^

、completly大丈夫thatsのと、この過負荷がテンプレートタイプのためにオーバーロードの解決を追い出されるべきと問題になることはありません。最初のエラーは私を夢中にさせるものです。

$ clang++ -std=c++14 sci_e1.cpp -o sci 
sci_e1.cpp:45:3: error: no matching function for call to 'add' 
    handler_provider<int, int>::add<my_add_handler>("test"); 
    ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 
sci_e1.cpp:17:15: note: candidate template ignored: invalid explicitly-specified argument for 
     template parameter 'F' 
    static void add(const std::string name) 
      ^
sci_e1.cpp:24:15: note: candidate template ignored: invalid explicitly-specified argument for 
     template parameter 'F' 
    static void add(const std::string name) 
      ^
1 error generated. 

しかし、私はここで間違っているところ、私はまだ理解していない:

クラン(3.9.0)は、もう少し正確です。私は何が欠けていますか?

おかげで、

セバスチャンより良いテストのために


は、ここに完全な例です:

#include <unordered_map> 
#include <string> 
#include <iostream> 

// Handler type 
using function_type = void(int); 

// Dispatch table 
std::unordered_map<std::string, function_type*> fn_handlers; 

// Handler provider (to install new handlers) 
template<class... Ts> 
struct handler_provider 
{ 
    // Overload for templates, such as 'test_handler' 
    template<template<class...> class F> 
    static void add(const std::string name) 
    { 
    handler_provider<Ts...>::add<F<Ts...>>(name); 
    } 

    // Overload for non-template (or already specialized) handlers (aka. function pointers) 
    template<function_type F> 
    static void add(const std::string name) 
    { 
    fn_handlers[name] = F; 
    } 
}; 


template<class A, class B> 
void test_handler(int v) 
{ 
    // Something here A and B are needed 
} 

void other_handler(int v) 
{ 
    // A handler without specialization 
} 

int main() 
{ 
    // Install handlers 
    handler_provider<int, int>::add<test_handler>("testii"); 
    handler_provider<double, int>::add<test_handler>("testdi"); 
    handler_provider<bool, bool, int>::add<other_handler>("otherbbi"); 

    // Dispatch 
    fn_handlers["testii"](5); // Sould call test_handler<int, int> 
    fn_handlers["testdi"](5); // Should call test_handler<double, int> 

    fn_handlers["otherbbi"](5); // Should call other_handler 
} 
+1

'add()'に指定されたテンプレートパラメータはテンプレートクラスです。 "test_handler"はテンプレートクラスではありません。これはテンプレート関数です。 2つは交換できません。 –

+0

ヒントありがとう!私はすでに 'F 'を関数としてaddメソッド内から直接使用しようとしたので、 "primary expression expected ..."というエラーが出ています。私はこのようなことをしようとしました: 'template