web-dev-qa-db-ja.com

enable_ifを使用してクラスコンストラクターを選択する

次のコードを検討してください。

#include <iostream>
#include <type_traits>

template <typename T>
struct A {
    int val = 0;

    template <class = typename std::enable_if<T::value>::type>
    A(int n) : val(n) {};
    A(...) { }

    /* ... */
};

struct YES { constexpr static bool value = true; };
struct NO { constexpr static bool value = false; };

int main() {
    A<YES> y(10);
    A<NO> n;
    std::cout << "YES: " << y.val << std::endl
              << "NO:  " << n.val << std::endl;
}

Enable_ifを使用して、一部のタイプのコンストラクターA :: A(int)のみを選択的に定義します。他のすべてのタイプには、デフォルトコンストラクターA :: A(...)があります。これは、置換が失敗した場合のコンパイラーのデフォルトのケースです。しかし、これは私にとって意味がありますコンパイラ(gccバージョン4.9.0 20130714)はまだ文句を言っています

sfinae.cpp: 'struct A'のインスタンス化:sfinae.cpp:19:11:
ここから必要sfinae.cpp:9:5:エラー: 'type'という名前のタイプはありません
'struct std :: enable_if'
A(int n):val(n){};

このようなものはコンストラクターに可能ですか?これは別のコンストラクター(copy-constructorおよびmove-constructor)で可能ですか?

44
tomas789

クラステンプレートをインスタンス化するときに値を解決する必要があるため、これは単一の既定のテンプレートパラメーターでは機能しないと思います。

コンストラクターテンプレートのインスタンス化の時点まで置換を延期する必要があります。 1つの方法は、テンプレートパラメーターをTにデフォルト設定し、コンストラクターに追加のダミーパラメーターを追加することです。

template<typename U = T>
A(int n, typename std::enable_if<U::value>::type* = 0) : val(n) { }
37
jrok

通常、これは匿名のデフォルト引数を使用して行われます:

A(int n, typename std::enable_if<T::value>::type* = 0) : val(n) {};

クラスのテンプレートパラメータをSFINAE outメソッドに使用することはできません。 SO 1つの方法は、intを置き換えるダミー型を追加することです。

参照: http://ideone.com/2Gnyzj

#include <iostream>
#include <type_traits>

template <typename T>
struct A {
    int val = 0;

    template<typename Integer
            ,typename  = typename std::enable_if<T::value && sizeof(Integer)>::type
            >
    A(Integer n) : val(n) {};

    A(...) {}
    /* ... */
};

struct YES { constexpr static bool value = true; };
struct NO { constexpr static bool value = false; };

int main() {
    A<YES> y(10);
    A<NO> n;
    std::cout << "YES: " << y.val << std::endl
              << "NO:  " << n.val << std::endl;
}

これは、メンバーテンプレートパラメーターを使用してコンストラクターをSFINAEするために機能しますが、テストは常にtrueであるため、チェックを汚染しません

9
Joel Falcou