jeudi 28 avril 2016

Is std::make_unique SFINAE-friendly?

I'm doing some template-meta-programming and I would like to implement a generic cloning function that selects a method of cloning depending on the validity of expressions via SFINAE (Substitution Failure Is Not An Error).

On this reference website it says that

The function

make_unique<T>( std::forward<Args>(args)... )

is equivalent to:

unique_ptr<T>(new T(std::forward<Args>(args)...))

Does this mean that the following code

template <typename T>
auto my_clone( const T & t ) -> decltype( std::make_unique<T>(t) )
{
    return std::make_unique<T>(t);
}

should be completely equivalent to

template <typename T>
auto my_clone( const T & t ) -> decltype( std::unique_ptr<T>( new T(t) ) )
{
    return std::unique_ptr<T>( new T(t) );
}

even when I have other overloads of the function my_clone? In other words: is std::make_unique() SFINAE-friendly?

If T is not copy constructible, then the latter code would not participate in overload resolution due to SFINAE.

Here's a small example that fails to compile on GCC 5.3 with C++14 turned on:

#include <memory>

// It does **not** work with this snippet:
template <typename T>
auto my_clone( const T & t ) -> decltype( std::make_unique<T>( t ) )
{
    return std::make_unique<T>( t );
}

/* // But it works with this snippet instead:
template <typename T>
auto my_clone( const T & t ) -> decltype( std::unique_ptr<T>( new T(t) ) )
{
    return std::unique_ptr<T>( new T(t) );
}*/

// This is another overload for testing purposes.
template <typename T>
auto my_clone( const T & t ) -> decltype(t.clone())
{
    return t.clone();
}  

class X
{
public:
    X() = default;

    auto clone() const
    {
        return std::unique_ptr<X>( new X(*this) );
    }

private:
    X( const X & ) = default;
}; 

int main()
{
    // The following line produces the compiler error: 
    // "call to 'my_clone' is ambiguous"
    const auto x_ptr = my_clone( X() ); 
}

Aucun commentaire:

Enregistrer un commentaire