2017-01-16 7 views
5

std::enable_ifをC++ 11でよりよく理解しようとしていて、最小の例を書くことを試みています。クラスがAであり、メンバ関数がvoid foo()で、クラステンプレートのタイプTに基づく実装。
以下のコードは望ましい結果を示していますが、まだ完全に理解していません。バージョンV2は動作しますが、V1では動作しません「冗長」タイプUが必要なのはなぜですか?enable_if:引数のないvoidメンバ関数の最小例

#include <iostream> 
#include <type_traits> 

template <typename T> 
class A { 

    public: 

     A(T x) : a_(x) {} 

     // Enable this function if T == int 
     /* V1 */ // template <   typename std::enable_if<std::is_same<T,int>::value,int>::type = 0> 
     /* V2 */ template <typename U=T, typename std::enable_if<std::is_same<U,int>::value,int>::type = 0> 
     void foo() { std::cout << "\nINT: " << a_ << "\n"; } 

     // Enable this function if T == double 
     template <typename U=T, typename std::enable_if<std::is_same<U,double>::value,int>::type = 0> 
     void foo() { std::cout << "\nDOUBLE: " << a_ << "\n"; } 

    private: 

     T a_; 

}; 

int main() { 
    A<int> aInt(1); aInt.foo(); 
    A<double> aDouble(3.14); aDouble.foo(); 
    return 0; 
} 

クラステンプレートパラメータに基づいvoid foo()機能の異なる実装を有するために、所望の結果、すなわちを達成するためのより良い方法はありますか?

+0

あなたの例は、 'enable_if'を適切に使用するものではありません。単純なオーバーロードは、あなたのケースを解決します。 'enable_if'は主に*推定された*テンプレートパラメータで役に立ちます。 –

+0

'std :: enable_if'を使うことは、推定された浮動小数点型を、例えば、整数型から分離するのに適しています。このような2つのタイプは、オーバーロードに適しています*。 – WhozCraig

+0

@KerrekSB @WhozCraigどのようにこの特定のケースで過負荷ですか?クラス外の定義 'void A :: foo(){}'と 'void A :: foo(){}'を使用することで、私の意図は、最終的なコードには必要な関数のバージョンしか含まれていないということです(つまり、そのような関数が呼び出されない場合、関数 'A :: foo()はありません)。 – untergam

答えて

2

私はこれはあなたの質問に完全に答えてくれませんが、あなたにはより良いアイデアと理解方法を教えてくれるかもしれません。std::enable_if

あなたがしている、次のと同じ機能を使用してfooのメンバ関数を置き換えることができます:

template<typename U=T> typename std::enable_if<std::is_same<U,int>::value>::type 
foo(){ /* enabled when T is type int */ } 

template<typename U=T> typename std::enable_if<std::is_same<U,double>::value>::type 
foo(){ /* enabled when T is type double */ } 

Aが戻っている間、私はどのようにenable_if作品のかなり良い理解を得て、残念ながら、私は忘れてしまったその複雑さの大部分と、それを使用するより現実的な方法を覚えておいてください。

+0

'std :: enable_if <>'にすでに含まれているので、関数の前に 'void'も削除する必要があると思います。しかし、この入力のために、私は何が起こっているのかを理解するために一歩近づくのを助けました。これがコンパイル時の多形性を達成する正当な方法だとお考えですか? – untergam

+0

@untergamおっと、いいキャッチ!私は今それを編集します。私はそれが正当な方法であると思う、良い方法があれば分かりません –

0

最初の質問と同様に、なぜV1が機能しないのですか? SFINAEは過負荷解決にのみ適用されますが、V1はタイプAがインスタンス化された時点でエラーを発生させます。これはオーバーロード解決のfoo()よりかなり前です。

可能な実装がたくさんあると思われます。これは、問題の実際のケースによって異なります。一般的なアプローチは、さまざまなテンプレートタイプで異なるAの部分をヘルパークラスに延期することです。

template <typename T> 
class A_Helper; 

template <> 
class A_Helper<int> { 
public: 
    static void foo(int value){ 
     std::cout << "INT: " << value << std::endl; 
    } 
}; 

template <> 
class A_Helper<double> { 
public: 
    static void foo(double value){ 
     std::cout << "DOUBLE: " << value << std::endl; 
    } 
}; 

template <typename T> 
class A { 
public: 

    A(T a) : a_(a) 
    {} 

    void foo(){ 
     A_Helper<T>::foo(a_); 
    } 

private: 
    T a_; 
}; 

Aの残りの部分は、一般的な方法で一度だけ宣言することができます - 異なる部分だけをヘルパーに延期されています。あなたの要求に応じて、可能なバリエーションがたくさんあります...

+0

お返事ありがとう@j_kubik。テンプレートヘルパークラスを使ったこのソリューションがどのように機能するのかを見ていますが、これはまさに私が最初に避けようとしていたコードブーティングのようなものです。私は 'enable_if'または少なくとも同様の短い構文で最小限のバージョンを好むでしょう。 – untergam

関連する問題