I am trying to conditionally enable a constructor template. With a fully C++11-compliant compiler, I know how to do this using an extra default template argument. However, I need to support VS2012, which has std::enable_if but does not support defaulted function template arguments.
With C++11, I would write the following:
template<typename T>
struct Class
{
template<typename O,
typename = typename std::enable_if<std::is_convertible<O*, T*>::value>::type>
Class(O*) {}
};
I tried the following, but it gives an error C4336 and various follow-up errors:
template<typename T>
struct Class
{
template <typename O>
Class(O*, typename std::enable_if<std::is_convertible<O*, T*>::value>::type *= nullptr)
{
}
};
Is there any way to make this work with VS2012?
Addition:
The usage of the class would be as follows:
struct X { };
struct X2 : X { };
struct Y { };
struct Client
{
Client(Class<X> x) {}
Client(Class<Y> y) {}
};
void test() {
X2* x2;
Client client(x2); // error C2668: ambiguous call to overloaded function
// (without std::enable_if)
}
You are so close to the solution !
template<typename T>
struct Class
{
template <typename O>
Class(O*, typename std::enable_if<std::is_convertible<O*, T*>::value>::type * = nullptr)
{
}
};
Did you spot the difference ? *=
inside the parameter list was parsed as the multiplication/assignment operator, not as a pointer type followed by a default argument. Hence, syntax errors.
This is because the C++ parser is specified to consume as many characters as possible when it forms a token (the so-called Maximum Munch Rule). Adding a space splits it into two separate tokens, as intended.