user1504193
user1504193

Reputation: 121

Boost enable_if in constructor

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

Answers (3)

mfontanini
mfontanini

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

David Hammen
David Hammen

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

Lol4t0
Lol4t0

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:

  1. You should still have double specialized common case to derive
  2. You should not call common case default constructor, but some specialized.

There 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

Related Questions