4

我正在尝试使用模板和 SFINAE 来做一些事情,我是其中的初学者。我正在浪费大量时间来完成每件最简单的事情。你能帮我理解它是如何工作的吗?

C< T , Ts... > 的构造函数采用 A< U > 或 B< U > 的 T 参数,但在这两种情况下具有不同的行为。我无法向你展示我试图这样做的一切。这是在我看来最不愚蠢的方式。

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 A<U>,它只能用于enable_if_A<U>::type确实是类型的类型。类型可以在调用的地方通过第一个参数推导,推导的类型U将被第二个参数替换。如果该替换失败,则模板化构造函数将被丢弃。

上面的解决方案是 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 回答
0

如果您不坚持使用 SFINAE,则可以通过使用具有部分特化的间接构造函数来轻松解决此问题,如下所示:

#include <iostream>

using namespace std;

template <typename T>
struct C
{
 T val;
 C() { init(); };
 void init() {};
};

template<> void C<string>::init() { val = "STR"; }
template<> void C<int>::init() { val = 5; }

int main () {
  C<int> x;
  C<string> y;

  cout << y.val << endl << x.val << endl;
}

此示例使用 int 和 string 而不是您的类型 A< U > 和 B< U >,但这应该没有区别(除了它使该示例可编译)。

于 2013-05-09T12:40:17.717 回答