Reputation: 975
I tried to create a template class that should detect any constructor by using SFINAE and variadic templates. Here is code of the template:
template <typename Type, typename ... Arguments>
struct IsConstructible
{
template <typename U, decltype(U(Arguments...))* = nullptr>
static char test();
template <typename U>
static long test(...);
static constexpr bool value = sizeof(test<Type>()) == sizeof(char);
};
However, when I test this with following type:
struct MyBadType {
MyBadType(int x) { }
};
the result of this:
IsConstructible<MyBadType, int>::value;
is 0. Is there anything wrong with my template checker? I am using MSVS 2015 express.
Upvotes: 3
Views: 187
Reputation: 65610
The code shouldn't compile; if MSVC does so then it's using extensions.
template <typename U, decltype(U(Arguments...))* = nullptr>
That decltype
expression doesn't make sense. U(Arguments...)
is a function type, but you want to get the type of constructing a U
from Arguments...
. You could use std::declval
for that:
template <typename U, decltype(U(std::declval<Arguments>()...))* = nullptr>
There is a second issue:
template <typename U, decltype(U(std::declval<Arguments>()...))* = nullptr>
static char test();
template <typename U>
static long test(...);
A call of test<type>()
would be ambiguous. The "classic" way to resolve the ambiguity is to give the preferred version a dummy parameter:
template <typename U, decltype(U(std::declval<Arguments>()...))* = nullptr>
static char test(int);
// here ^^^
template <typename U>
static long test(...);
Then you call the function like test<type>(0)
.
See this blog post for a more flexible way to resolve overload ambiguities.
Upvotes: 3