我正在尝试用模板和SFINAE制作一些东西,我是初学者。我浪费了大量的时间来完成最简单的工作。你能帮我理解它的工作原理吗?
C的构造函数< T,Ts ...>采用T参数,该参数是A< U>或者B< U>,但在这两种情况下具有不同的行为。我无法告诉你我试图这么做的一切。这对我来说似乎是最不愚蠢的。
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;}
};
答案 0 :(得分: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
将替换为第二个参数。如果该替换失败,则模板化构造函数将被丢弃。
上述解决方案与C ++ 03兼容。如果你有一个C ++ 11编译器,你可以做同样的事情,而不需要构造函数的额外参数(即不添加额外的参数;如果我得到正确的语法,则不是100%):)
template <typename T>
template <typename U, typename _ = typename enable_if_A<U>::type>
C<T>::C<U>(U const &) {...}
答案 1 :(得分: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&lt; U>和B&lt; U&gt;,但这应该没有区别(除了它使这个例子可编辑)。