2016-06-28 27 views
2

の呼び出し可能な署名を検証それでは、私はこのような一般的な機能を持っているとしましょう:C++テンプレートの種類

template<typename TFunc> 
void templFunc(TFunc func) { 
    func(3, 6); 
} 

は、私は関係なく、それはSTDのかどうかのTFuncの署名を検証することができ、コンパイル時にどのような方法があります: :任意の種類の関数またはラムダまたは関数参照。私はちょうどTFuncがstatic_assertとのシグネチャvoid(int、int)か同様のものであることを確認したいので、私は非ゴミエラーメッセージを生成することができます。

+0

ラムダが必要条件ではありませんならば、あなたは 'static_assert(STD :: is_same ::値、 "エラー")を使用することができます;' – iammilind

答えて

0

あなたが使用することができます。

template<typename TFunc> 
void templFunc(TFunc func) { 
    static_assert(std::is_void<decltype(func(0,0))>::value, 
       "Bad template argument. The return type is not void"); 
    func(3, 6); 
} 
  1. これは、関数の戻り値の型がvoidであることを確認します。
  2. 関数が2つの引数を取らない場合は、func(3,6); - 2回失敗します。一度、static_assert行に入り、次の行に1回。

  3. 引数型がintまたはintが昇格、変換、またはキャスト可能なその他の型の場合、関数呼び出しは成功します。引数型がintであることを確認するには、いくつかの追加作業が必要です。私はそれが何を伴うのか分かりません。

テストプログラム:

#include <type_traits> 

template<typename TFunc> 
void templFunc(TFunc func) { 
    static_assert(std::is_void<decltype(func(0,0))>::value, "Bad template argument. The return type is not void"); 
    func(3, 6); 
} 

void foo() 
{ 
} 

void bar(int x, int y) 
{ 
} 

int baz(int x, int y) 
{ 
    return 0; 
} 

struct Functor 
{ 
    void operator()(long, long) 
    { 
    } 
}; 

int main() 
{ 
    templFunc(foo); // Not OK. Two few arguments 
    templFunc(bar); // OK 
    templFunc(baz); // Not OK. Wrong return type 
    templFunc([](int, int) -> void {}); // OK 
    templFunc(Functor()); // OK 
} 
0

このような何かが、あなたはテンプレートパラメータに基づいて主張を行う場合にのみ、(SFINAEを使用して動作します。理由は正確にわからない、と私はそれが最も興味深いものになるだろうと思います一部:)):

#include <type_traits> 

template<typename TFunc> 
typename std::enable_if<std::is_same<typename std::result_of<TFunc(int, int)>::type, void>::value >::type templFunc(TFunc func) 
{ 
    func(3, 6); 
} 

template<typename TFunc> 
typename std::enable_if<!std::is_same<typename std::result_of<TFunc(int, int)>::type, void>::value >::type templFunc(TFunc func) 
{ 
    static_assert(std::is_same<typename std::result_of<TFunc(int, int)>::type, void>::value, "error; invalid function"); 
} 

auto a = [](int, int) {}; 
auto b = [](int x, int y) { return x + y; }; 

int main() 
{ 
    templFunc(b); 
    return 0; 
} 
+0

標準によると、 'dcl.dcl'、" _ static_assert-declarationで定数式は定数式(5.19)でなければなりません **文脈上は** boolに変換されます... "...だから、テンプレート依存関係は 'static_assert'式には含まれていません**、関数テンプレートのコンテキスト外で評価され、関数テンプレートが過負荷解決のために評価されていないかどうかに依存しませんか?それはいつも評価されていますか? – mkal

+0

これは 'auto a = [](long、int){};'と定義されたラムダ関数に対して 'true'を返す。 – user2296177

+0

@ user2296177:ええ、' double'または暗黙的に 'int'に変換できるもの。また、戻り値の型が間違っていて、引数の数または型が間違っている場合にのみ、フレンドリなエラーメッセージが返されます... – mkal

1

だから私はtype_traitsのもののいくつかの周りいじって、私は全体の署名を検証し、何か、だけではなく、戻り値を持っていると思う、とあなたはCREすることができます署名が一致しないときに判読不能なテンプレートエラーではなく、static_assertsを読みやすくなりました。これは悪い解決策ですか?

#include <functional> 

template<typename, typename, typename = void> 
struct is_signature : std::false_type {}; 

template<typename TFunc, typename Ret, typename... Args> 
struct is_signature<TFunc, Ret(Args...), 
     typename std::enable_if< 
      std::is_convertible< 
       TFunc, 
       std::function<Ret(Args...)> 
      >::value 
     >::type 
    > : public std::true_type 
    {}; 

// works on both functions and lambda's 
void blah(int, int) { 
} 

template<typename TFunc> 
void templFunc(TFunc func) { 
    static_assert(is_signature<TFunc, void(int, int)>::value, "Not gonna work! more info follows:"); 
    func(3, 6); 
} 

int main() { 
    auto b = [](int, int) -> void { 
    }; 

    auto c = [](int) -> void { 
    }; 

    static_assert(is_signature<decltype(b), void(int, int)>::value, "b convertible to a std::function<void(int, int), so this checks out!"); 
    static_assert(is_signature<decltype(b), void(int)>::value, "b not convertible to a std::function<void(int)>, so this will error in compilation."); 
    static_assert(is_signature<decltype(blah), void(int, int)>::value, "blah convertible to a std::function<void(int, int), so this checks out!"); 
    static_assert(is_signature<decltype(blah), void(int)>::value, "blah not convertible to a std::function<void(int)>, so this will error in compilation."); 

    templFunc(b); // <- ok 
    templFunc(c); // <- static assertion : not gonna work! 
    return 0; 
} 
+0

これは正しく動作していますか? 'auto a = [](int、int){return 0;}に対して' is_signature :: value == true'を返します。 }; ' – user2296177

+0

また、' auto a = [](int、char){}; ' – mkal

+0

@ user2296177と@mkalに対してもエラーはありません。 'auto b = [](int、int){return 0;}'は 'std :: function 'に代入されます。 'std :: function と書くと、meh = b;'?私は間違いなく、どのようにそれらのタイプのコンバーチブルですか? – FatalCatharsis