2017-11-28 9 views
6

後で呼び出すためにstd::functionを格納するテンプレートクラスを作成しています。ここでは簡体コードは次のとおりです。enable_ifを使用したテンプレートメソッドの特殊化

template <typename T> 
struct Test 
{ 
    void call(T type) 
    { 
     function(type); 
    } 
    std::function<void(T)> function; 
}; 

問題が

void call(void type) 

が未定義となるため、このテンプレートはvoidタイプ用にコンパイルしないということです。

template <> 
void Test<void>::call(void) 
{ 
    function(); 
} 

はまだcall(T Type)の宣言と互換性がないためvoidタイプのためにそれを専門

は、問題を軽減しません。

ので、C++ 11の新機能を使用して、私はstd::enable_ifみました:

typename std::enable_if_t<std::is_void_v<T>, void> call() 
{ 
    function(); 
} 

typename std::enable_if_t<!std::is_void_v<T>, void> call(T type) 
{ 
    function(type); 
} 

をしかしそれは、Visual Studioでコンパイルされません。

エラーC2039: 'type' を:ではありません'std :: enable_if'のメンバー

この問題にどのように対処しますか?

+1

SFINAEは*推定値*テンプレートパラメータに対してのみ機能します。 –

答えて

2

SFINAEは、クラス/構造体のテンプレートパラメータでのみ機能しません。

テンプレートメソッドには、メソッドのテンプレートパラメータを含む条件があります。

だからあなたはあなたがUT

template <typename U = T> 
    std::enable_if_t< std::is_same<U, T>::value 
        && std::is_void<U>::value> call() 
    { function(); } 

    template <typename U = T> 
    std::enable_if_t<std::is_same<U, T>::value 
        && !std::is_void<U>::value> call(T type) 
    { function(type); } 

p.s:std::enable_if_tであることはそれほど前typenameを必要としないタイプであることを確認したい場合は、

template <typename U = T> 
    std::enable_if_t<std::is_void<U>::value> call() 
    { function(); } 

    template <typename U = T> 
    std::enable_if_t<!std::is_void<U>::value> call(T type) 
    { function(type); } 

を書いたりする必要があります。

p.s.2:C++ 11にタグ付けしましたが、使用例はstd::enable_if_t、すなわちC++ 14、std::is_void_v、つまりC++ 17

+0

SFINAEがなぜあなたのケースで動作し、私のものではないのかを説明する繊細さは完全に理解していませんでしたが、コードはコンパイルされます。あなたの追加のコメントをありがとう。 –

+0

プロダクションレベルのコードでは、 'enable_if_t'内に' std :: is_same_v 'を入れて、コンパイル時に' U'と 'T'以外の明示的な' call () 'を打ち消すこともできます。 – TemplateRex

4

クラス全体特化:あなたはvoidを使用するように固執していない、とあなたの意図がに実際に可変長引数テンプレートを使用し、その後、パラメータなしTestを使用することが可能である場合

template <> 
struct Test<void> 
{ 
    void call() 
    { 
     function(); 
    } 
    std::function<void()> function; 
}; 
+0

確かに動作しますが、最近のSFINAE構造を使用することで、クラス全体を専門にすることを避けることがアイデアでした。 –

2

を:

template <typename ...T> 
struct Test 
{ 
    void call(T ...type) 
    { 
     function(type...); 
    } 
    std::function<void(T...)> function; 
}; 

このように、任意の数のパラメータを設定できます。

Test<> t; 
t.call(); 

だから、これは正確にあなたが望んでいた構文ではなく、そこに専門化のための必要がなく、任意の数のパラメータをサポートしているので、このソリューションは、より柔軟である:あなたがパラメータを持たないようにしたい場合は、これを使用します。

+0

私はコードの簡略化したバージョンを与えましたが、実際はボイドの戻り値の型を扱うことでした。私はあなたが提案したバリデーショナルテンプレートで入力パラメータを処理しました。 –

関連する問題