4

テンプレートと SFINAE で何かを作ろうとしていますが、初心者です。最も単純なことをすべて機能させるために、膨大な時間を無駄にしています。それがどのように機能するかを理解するのを手伝ってもらえますか?

C< T , Ts... > のコンストラクターは、 A< U > または B< U > のいずれかである T パラメーターを取りますが、これら 2 つのケースでは異なる動作をします。私がそうしようとしたすべてをお見せすることはできません。これが私には最も愚かに思えた方法です。

template<typename T> class A{
public: A(){} };

template<typename T> class B{
public: B(){} };

template<typename T> struct enable_if_A         {};
template<typename T> struct enable_if_A< A<T> > {typedef A<T> type;};

template<typename T> struct enable_if_B         {};
template<typename T> struct enable_if_B< B<T> > {typedef B<T> type;};

template<typename T,typename... Ts> class C{
public:
    C(typename enable_if_A<T>::type const &p){cout << "A" << endl;}
    C(typename enable_if_B<T>::type const &p){cout << "B" << endl;}
};

// ...

A<float> a;
B<float> b;

C<A<float> > ca(a); // error: no type named ‘type’ in ‘struct enable_if_B<A<float> >'
C<B<float> > cb(b); // error: no type named ‘type’ in ‘struct enable_if_A<B<float> >'

注: g++ (Ubuntu/Linaro 4.6.1-9ubuntu3) 4.6.1 を使用しています。アップグレードする必要がありますか?

ありがとう

編集:詳細については、私も(特に)試しました:

template<typename T,typename... Ts> class C{
public:
    template<>
    C(typename enable_if_A<T>::type const &p){cout << "A" << endl;}
    template<>
    C(typename enable_if_B<T>::type const &p){cout << "B" << endl;}
};
//explicit specialization in non-namespace scope ‘class bcifs::C<T, Ts>’

//////////////////////////////////////////////////////////////////////////

template<typename T,typename... Ts> class C{
public:
    template<typename E=void>
    C(typename enable_if_A<T>::type const &p){cout << "A" << endl;}
    template<typename E=void>
    C(typename enable_if_B<T>::type const &p){cout << "B" << endl;}
};
// error: no type named ‘type’ in ‘struct enable_if_B<A<float> >'

//////////////////////////////////////////////////////////////////////////

template<typename T> struct enable_if_A         {};
template<typename T> struct enable_if_A< A<T> > {typedef void type;};

template<typename T> struct enable_if_B         {};
template<typename T> struct enable_if_B< B<T> > {typedef void type;};

template<typename T,typename... Ts> class C{
public:
    template<typename E=void>
    C(T const &p);

    C<typename enable_if_A<T>::type>(T const &p){cout << "A" << endl;}
    C<typename enable_if_B<T>::type>(T const &p){cout << "B" << endl;}
};
// error: invalid declarator before ‘(’ token

//////////////////////////////////////////////////////////////////////////

template<typename T> class C{
public:
    template<>
    C(T const &p,typename enable_if_A<T>::type * = 0){cout << "A" << endl;}
    template<>
    C(T const &p,typename enable_if_B<T>::type * = 0){cout << "B" << endl;}
};
// error: explicit specialization in non-namespace scope ‘class C<T>’
// error: no type named ‘type’ in ‘struct enable_if_B<A<float> >’

//////////////////////////////////////////////////////////////////////////

template<typename T> class C{
public:
    template<typename U>
    C(T const &p,typename enable_if_A<T>::type * = 0){cout << "A" << endl;}
    template<typename U>
    C(T const &p,typename enable_if_B<T>::type * = 0){cout << "B" << endl;}
};
// error: no type named ‘type’ in ‘struct enable_if_B<A<float> >’
// error: no matching function for call to ‘C<A<float> >::C(A<float>&)’

//////////////////////////////////////////////////////////////////////////

template<typename T> struct enable_if_A         {};
template<typename T> struct enable_if_A< A<T> > {typedef void type;};

template<typename T> struct enable_if_B         {};
template<typename T> struct enable_if_B< B<T> > {typedef void type;};

template<typename T> class C{
public:
    template <typename U>
    C(A<U> const & r, void* _ = 0);
};

template <typename T>
template <typename U>
C<T>::C<T>(A<U> const & r, typename enable_if_A<U>::type* _ = 0) {
    cout << "A" << endl;
}
// error: ISO C++ forbids declaration of ‘C’ with no type [-fpermissive]
// error: function template partial specialization ‘C<T>’ is not allowed
// error: no ‘int C<T>::C(const A<U>&, typename enable_if_A<U>::type*)’ member function declared in class ‘C<T>’
// C<T>::C<U>(... does the same

申し訳ありませんが、ソリューションを実行できませんでした。私はついに見つけました:

// dummy-function-parameter-ed version :

template<typename T> class C{
public:
    template <typename U>
    C(A<U> const &r,typename enable_if<is_same<A<U>,T>::value>::type* = 0){cout << "A" << endl;}

    template <typename U>
    C(B<U> const &r,typename enable_if<is_same<B<U>,T>::value>::type* = 0){cout << "B" << endl;}
};

// and the dummy-template-parameter-ed version :

template<typename T> class C{
public:
    template<typename U,typename E = typename enable_if<is_same<A<U>,T>::value>::type>
    C(A<U> &r){cout << "A" << endl;}

    template<typename U,typename E = typename enable_if<is_same<B<U>,T>::value>::type>
    C(B<U> &r){cout << "B" << endl;}
};
4

2 に答える 2

8
template<typename T,typename... Ts> class C{
public:
    C(typename enable_if_A<T>::type const &p){cout << "A" << endl;}
    C(typename enable_if_B<T>::type const &p){cout << "B" << endl;}
};

これは間違っていますが、あなたはすでにそれを知っています :) その理由は、SFINAE はテンプレート レベルでしか適用できないのに、それをテンプレートのメンバーに適用しようとしているからです。つまり、上記のテンプレートの SFINAE は、さまざまなC<T>型にのみ適用できますが、のコンストラクターには適用できませんC<T>

SFINAE をコンストラクターに適用できるようにするには、コンストラクターをテンプレートにする必要があります。しかし、あなたの場合、それは別の制限につながります。コンストラクターは、(コンストラクターがテンプレート化されている場合でも) テンプレート引数を指定できない特別な関数です。つまり、テンプレートの型は、呼び出しの場所から推定する必要があります。しかし、ネストされた型は推定できません...

コンストラクターのシグネチャを変更することで、この制限を回避できます。

template <typename T>
template <typename U>
C<T>::C<U>(A<U> const & r, typename enable_if_A<U>::type* _ = 0) {
    // ...
}

この場合、クラスCは を受け取るテンプレート化されたコンストラクターを持つテンプレートです。これは、実際に型A<U>である型に対してのみ使用できます。enable_if_A<U>::type型は最初の引数を介して呼び出しの場所で推定でき、推定された型Uは 2 番目の引数で置換されます。その置換が失敗した場合、テンプレート化されたコンストラクターは破棄されます。

上記のソリューションは C++03 と互換性があります。C++11 コンパイラを使用している場合は、コンストラクタに追加の引数を必要とせずに同じことを行うことができます (つまり、追加の引数を追加せずに; 構文が正しい場合は 100% ではありません:)):

template <typename T>
template <typename U, typename _ = typename enable_if_A<U>::type>
C<T>::C<U>(U const &) {...}
于 2013-04-30T13:22:22.110 に答える