Reputation: 121
I have a templated class, and I want to enable a certain constructor only when the type is a double. What's wrong with this code?
template<typename T>
class B: public A<T>
{
public:
B(int arg1=0, typename boost::enable_if_c<boost::is_same<T, double>::value>=0);
}
int main(int argc,char *argv[])
{
B<double> B( 6, 6 );
}
I'm getting the error: "default argument for parameter of type ‘boost::enable_if_c’ has type ‘int’" but I'm not sure what is meant by this.
Thank you so much in advance.
Upvotes: 0
Views: 1312
Reputation: 21910
Well, you can't really do that. If you provide some T
which is not double
, then the compiler will try to resolve enable_if_c<false>::type
, which will fail, making the whole class instantiation fail, not just the constructor.
You can use C++11's default function template arguments to achieve the same.
The code below implements that using C++11 version of the boost
features you used in your code:
#include <type_traits>
template<typename T>
class B {
public:
// T == double -> this ctor can be used
template<typename U = T, class = typename std::enable_if<std::is_same<U, double>::value>::type>
B(int arg1, double arg2) {}
// Default ctor, available to every class.
B() {}
};
int main(int argc,char *argv[])
{
B<double> b_double( 6, 6 );
B<int> b_int;
// This line fails
//B<int> b_fails(6, 6);
}
Upvotes: 7
Reputation: 33126
B(int arg1=0, typename boost::enable_if_c<boost::is_same<T, double>::value>=0);
You forgot the second argument to boost::enable_if_c
which specifies the type, you forgot the ::type
, and you forgot a parameter name.
If you want something along the lines of B(int arg1=0, int arg2=0)
, use
B(int arg1=0,
typename boost::enable_if_c<boost::is_same<T, double>::value, int>::type arg2=0);
Even better, don't use the underscore c version of enable if. Just use enable if:
B(int arg1=0,
typename boost::enable_if<boost::is_same<T, double>, int>::type arg2=0);
Upvotes: 0
Reputation: 12557
You cannot use SFIANE in this case, because it works only if substitution of function template argument flails, not when substitution of class template argument fails.
What you need is specialization.
But as I understand, you should copy implementation of common case in your double
case, but only add new constructor.
In this case I suggest I little wired technique: You can derive from common case in your specialization.
Then you face 2 problems:
double
specialized common case to deriveThere we go:
template<typename T, bool = false>
class B
{
public:
B() { std::cout << "B common\n"; }
void yahoo() { std::cout << "yahoo!\n"; }
protected:
struct internal_t;
B(internal_t*){}
};
template <>
struct B<double, false>: public B<double, true>
{
B(int, int):B<double, true>(0) { std::cout << "B double\n"; }
};
int main(int argc,char *argv[])
{
B<int> ib;
B<double> b(2,5);
ib.yahoo();
b.yahoo();
}
Upvotes: 2