2016-07-23 10 views
2

私の質問に複数の選択肢からコンストラクタを選択するSFINAEを使用する方法この問題を拡張したものです。クラステンプレートのパラメータ型がデフォルトコンストラクタブルかどうかに応じてコンストラクタの動作を変更したいと思います。これを行うための最善の方法は、2つのコンストラクタを同じ使用法で使用することですインスタンス化ごとにコントラクターの両方のバージョンがint otherNにテンプレート化されているのに対し、私はenable_ifで選択的に有効にしようとしていないと、コンストラクターのどちらのバージョンもテンプレート関数ではないため、私のケースも異なります。はC++ 11

上記の質問への受け入れ答えのコメントは以下の最小限の例を作成するために私を導いた、this siteに私を導いた:私は最初をコメントアウト場合

#include <iostream> 
#include <type_traits> 

namespace detail { 
    enum class enabler {}; 
    enum class disabler {}; 
} 

template <typename Condition> 
using EnableIf = typename std::enable_if<Condition::value, detail::enabler>::type; 

template <typename Condition> 
using DisableIf = typename std::enable_if<!Condition::value, detail::disabler>::type; 

template<typename T> 
struct A { 

    T data; 

    // Valid if T is default-construtible; SFINAE otherwise 
    template<EnableIf<std::is_default_constructible<T>>...> 
    A() { std::cout << "Data defaulted" << std::endl; } 


    // Valid if T is *not* default-constructible; SFINAE otherwise 
    template<DisableIf<std::is_default_constructible<T>>...> 
    A() : data(0) { std::cout << "Data zeroed" << std::endl; } 
}; 

// struct which is not default-constructible 
struct B { 
    B() = delete; 
    B(int) {} 
}; 

int main() 
{ 
    A<int> x; // int is default-constructible 
    A<B> y; // class B is not default-constructible 

    return 0; 
} 

私は(-std=c++11で)これをコンパイルすることができますxまたは2番目のコンストラクタの宣言とyの宣言を使用して、私はどちらもしたくないのですが、コンパイラはtypeという名前の型がないと文句を言うと、std::enable_if<false, >にあります。

this質問への回答は、同様の問題に別のアプローチをとっていますが、アプローチを組み合わせて動作することができる十分な要素はわかりません。

+0

[ほぼ静的-IF(https://rmf.io/cxx11/almost-static-if)リンクを更新する必要があります。 – tukra

+0

修正済み、ありがとう – user1476176

答えて

4

ない理想的な、しかし、これは仕事が行われます:

#include <iostream> 
#include <type_traits> 

template<typename T> 
struct A { 

    T data; 

    A() : A((std::is_default_constructible<T> *)nullptr) {} 

private: 
    A(std::true_type *) { std::cout << "Data defaulted" << std::endl; } 

    A(std::false_type *) : data(0) { std::cout << "Data zeroed" << std::endl; } 
}; 

// struct which is not default-constructible 
struct B { 
    B() = delete; 
    B(int) {} 
}; 

int main() 
{ 
    A<int> x; // int is default-constructible 
    A<B> y; // class B is not default-constructible 

    return 0; 
} 
+1

ポインタを削除し、代わりに 'std :: is_default_constructible :: type'を渡すと、imoを読みやすくなります。そうでなければ+1します。 – davidhigh

0

をまたTとそのデフォルト構築可能能力に応じて、2つの代替クラスの実装を作成することができます。

#include <type_traits> 
#include <iostream> 

template <class T, class = void> 
struct A_parent; 

template <class T> 
struct A_parent<T, typename std::enable_if<std::is_default_constructible<T>::value>::type> { 
    T data; 
    A_parent() { std::cout << "Default constructable" << std::endl; } 
}; 

template <class T> 
struct A_parent<T, typename std::enable_if<!std::is_default_constructible<T>::value>::type> { 
    T data; 
    A_parent(): data(0) { std::cout << "Not default constructable" << std::endl; } 
}; 

template <class T> 
struct A: A_parent<T> { 
    /* further implementation */ 
}; 

struct B { 
    B() = delete; 
    B(int) {} 
}; 

int main() { 
    A<int> a1; 
    A<B> a2; 
} 

出力:

Default constructable 
Not default constructable 
2

@サムのタグ送信ソリューション以外にも、コンストラクタの10、しかし、あなたは次の点に注意する必要が:

  1. std::is_default_constructibleに使用するテンプレートパラメータがTすることはできません、代わりにあなたが(Tにデフォルト設定することができます)、「新しい」テンプレートパラメータを必要とします。 std::enable_if to conditionally compile a member function

  2. cppreference.comからの引用:詳細については、このSO質問/回答を参照してください

よくある間違いは 、デフォルトのテンプレート引数での異なる2つの関数テンプレートを宣言することです。デフォルトの テンプレート引数は関数テンプレートの署名の一部ではなく、 同じ署名を持つ2つの異なる関数テンプレートを宣言するのは であるため、これは不正です。

これは、次のコードにつながる:

#include <iostream> 
#include <type_traits> 

template<typename T> 
struct A { 

    T data; 

    // Valid if T is default-constructible; SFINAE otherwise 
    template<typename X = T, typename SFINAE = typename std::enable_if<std::is_default_constructible<X>::value>::type, typename P = SFINAE> 
    A() { std::cout << "Data defaulted" << std::endl; } 


    // Valid if T is *not* default-constructible; SFINAE otherwise 
    template<typename X = T, typename = typename std::enable_if<!std::is_default_constructible<X>::value>::type> 
    A() : data(0) { std::cout << "Data zeroed" << std::endl; } 
}; 

// struct which is not default-constructible 
struct B { 
    B() = delete; 
    B(int) {} 
}; 

int main() 
{ 
    A<int> x; // int is default-constructible 
    A<B> y; // class B is not default-constructible 

    return 0; 
} 

live example

+0

実際の例では '-std = C++ 14'を使用していて、' -std = C++ 11'を使用するとコンパイルできないことに気付きました。どのような変更が、これを14では可能にしますが、11ではできません。 – user1476176

+0

@ user1476176コードをC++ 11互換に更新しました。唯一の変更は 'std :: enable_if_t'の代わりに' std :: enable_if'を使うことでした。 –