5

私はそのようなコンストラクターを持っています:

class MyClass
{
    template<class TI> MyClass(TI first, TI last);
};

template<class TI> MyClass::MyClass(TI first, TI last)
{
    ;
}

このコンストラクターを有効にするのは、TIがイテレーターである場合のみです(つまり、TIにはiterator_categoryがあると思います)。(宣言と定義で)デフォルトのテンプレートパラメータとしてenable_ifを使用してC ++ 2011でそれを行う方法は?

どうもありがとうございます。

4

1 に答える 1

12

それはあなたが望むものに依存します。他に過負荷がない場合は、何もしなくても問題ありません。必要な操作を提供しない型が渡されると、コンパイラーはエラーを生成します。

本当にイテレータに限定したい場合はstatic_assert、「あいまいな関数呼び出しの代わりに、素敵なカスタムエラーメッセージでエラーを生成するので、これを行うことをお勧めします。これが私が見つけることができるすべての膨大な数のオーバーロードです:無限のリストに従いますオーバーロードの「または「機能が見つかりませんでした。自分で見つけてください」。

競合する別のテンプレート化されたオーバーロードがある場合は、実際にenable_ifが必要です。enable_ifをC++11の機能で使用する方法と、デフォルトのテンプレートパラメーターがあまり適切でない理由についてブログに投稿しました。私は代わりにこのようなもので解決しました:

enum class enabler {};

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


class MyClass
{
    template<class TI, EnableIf<is_iterator<TI>>...> MyClass(TI first, TI last);
};

template<class TI, EnableIf<is_iterator<TI>>...> MyClass::MyClass(TI first, TI last)
{ /* blah */ }

今必要なのは、テストの特性だけです。の存在をテストするiterator_categoryだけで十分だと思いますstd::iterator_traitsが、ポインターはイテレーターであり、ネストされたtypedefがないため、を使用してテストする必要があります。

これは、SFINAEを使用する通常の手法で実行できます。C ++ 11では、次のことを行います。

template <typename T>
struct sfinae_true : std::true_type {};

struct is_iterator_tester {
    template <typename T>
    static sfinae_true<typename std::iterator_traits<T>::iterator_category> test(int);

    template <typename>
    static std::false_type test(...);
};

template <typename T>
struct is_iterator : decltype(is_iterator_tester::test<T>(0)) {};

とはいえ、これはデフォルトの関数パラメーターを使用する従来の手法で実行できた可能性があります。

class MyClass
{
    template<class TI>
    MyClass(TI first, TI last,
            typename std::iterator_traits<T>::iterator_category* = nullptr)
};

template<class TI>
MyClass::MyClass(TI first, TI last,
                 typename std::iterator_traits<T>::iterator_category*)
{ /* blah */ }
于 2012-08-10T09:41:35.660 に答える