2016-08-12 17 views
2
enum class enabler{}; 

template<typename T> 
class X { 
    template<typename std::enable_if<std::is_class<T>::value,enabler>::type = enabler()> 
    void func(); 
    void func(int a); 
    void func(std::string b); 
}; 

このクラスには、funcの3つのオーバーロードがあります。クラス/非クラス型の両方で使用可能な2番目/ 3番目のバージョンが必要であり、最初のバージョンはクラス型でのみ使用できる必要があります。上記のようにenable_ifを使用しようとすると、クラス以外の型のクラスインスタンス化によってコンパイルエラーが発生します。オーバーロードでenable_ifを使用する方法

+3

SFINAEは、*演繹*型でのみ動作します。 –

+1

あなたはもっと詳しく教えていただけますか? – mkmostafa

+0

実際にsfinaeを使用する必要はありません。あなたのケースでは 'static_assert'で十分です。私の(遅い)答えの中の最小の例を見てください。 – skypjack

答えて

1

SFINAEを使用するには、テンプレートの引数を推測する必要があります。あなたのケースではをインスタンス化しようとするまでにTが既に分かっているので、enable_ifの条件がfalseの場合、SFINAEの代わりにハードエラーが発生します。

エラーを修正するには、デフォルト値がTのテンプレートパラメータを追加し、enable_ifチェックでこの新しいパラメータを使用します。今度は控除が発生し、SFINAEは非クラス型のために取り込むことができます。

template<typename U = T, 
     typename std::enable_if<std::is_class<U>::value,enabler>::type = enabler()> 
void func(); 

そして、あなたが本当にどちらか専用enablerタイプを必要としない、これはあなたが何かを有効または無効にされていない、あまりにも

template<typename U = T, 
     typename std::enable_if<std::is_class<U>::value, int>::type* = nullptr> 
void func(); 
+0

このアプローチの欠点は明示的なテンプレートパラメータで 'func()'を実行できることです。 'Tunc'がクラス –

+0

@AndreiRでなくても' func () 'はクラスオーバーロードを引き起こします。はい、足で自分を撃ってみたいと思うなら、いつでもそれを行うための方法を見つけることができます。 – Praetorian

+0

@Praetorian 'template :: value、int> :: type * = nullptr>のようなガードパラメータパックを引き続き使用できますfunc(); '明示的なテンプレートパラメータは噛み砕かれます。 – skypjack

1

私はあなたがここにenablerにするために行っているものを本当にわからないんだけど、あなたはTfuncによって推定されていないので、あなたのメンバ関数の宣言が有効である必要がありますので、あなたがしようとしているものを行うことはできません。過剰な負荷を追加するために必要なものを達成するには、適度に考案された継承を使用できます。

struct XBaseImpl { 
    // whatever you want in both versions 
    void func(int a) { } 
    void func(std::string b) { } 
}; 

template <typename, bool> struct XBase; 

// is_class is true, contains the extra overload you want 
template <typename T> 
struct XBase<T, true> : XBaseImpl { 
    static_assert(std::is_class<T>{}, ""); // just to be safe 
    using XBaseImpl::func; 
    void func() { } // class-only 
}; 

// is_class is false 
template <typename T> 
struct XBase<T, false> : XBaseImpl { }; 

template<typename T> 
class X : public XBase<T, std::is_class<T>{}> { }; 
0

動作します。
ある特定のケースでコンパイル時エラーが発生するだけです。
あなたはsfinaeに頼る必要はないので、static_assertで十分です。最小限、実施例として、

#include<string> 

template<typename T> 
class X { 
public: 
    void func() { 
     static_assert(std::is_class<T>::value, "!"); 
     // do whatever you want here 
    } 

    void func(int a) {} 
    void func(std::string b) {} 
}; 

int main() { 
    X<int> x1; 
    X<std::string> x2; 

    x2.func(42); 
    x2.func(); 

    x1.func(42); 
    // compilation error 
    // x1.func(); 
} 

SOのユーザーが私を言ったら:これはsfinaeされていない、これは - 置換の失敗は、常にエラーです - このケースでは、あなたがしなければなりません代わりにstatic_assertとしてください。
上記の例に示すように、static_assertはsfinaeよりも書きやすく理解しやすく、その作業も同様です。

関連する問題