Alexander Bily
Alexander Bily

Reputation: 975

C++ detect any constructor with SFINAE

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

Answers (1)

TartanLlama
TartanLlama

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).

Live Demo


See this blog post for a more flexible way to resolve overload ambiguities.

Upvotes: 3

Related Questions