Search code examples
c++c++11c++14unique-ptrstdbind

Error binding make_unique


I'm having trouble using std::bind with std::make_unique.

I have an object to whose constructor I pass factory functions for making std::unique_ptrs of objects of another class type.

Using VS2013, this works:

Tester tester( 
    [](){return std::make_unique<AlphaBetaSingleThreadSSE>( 0,7 ); },
    [](){return std::make_unique<AlphaBetaSingleThread>( 0,7 ); },
    20 );

This gives me compile errors:

Tester tester( 
    std::bind( std::make_unique<AlphaBetaSingleThreadSSE>,0,7 ),
    std::bind( std::make_unique<AlphaBetaSingleThread>,0,7 ),
    20 );

The error messages state:

error C2512: 'AlphaBetaSingleThread' : no appropriate default constructor available

error C2512: 'AlphaBetaSingleThreadSSE' : no appropriate default constructor available

Why does the std::bind approach fail?


Solution

  • std::make_unique is defined as follows:

    § 20.8.1.4 [unique.ptr.create]

    template <class T, class... Args> unique_ptr<T> make_unique(Args&&... args);
    

    1 Remarks: This function shall not participate in overload resolution unless T is not an array.

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

    By explicitly instantiating this function template with std::make_unique<AlphaBetaSingleThreadSSE> you end up with the following specialization:

    std::unique_ptr<AlphaBetaSingleThreadSSE> make_unique()
    {
        return std::unique_ptr<AlphaBetaSingleThreadSSE>(new AlphaBetaSingleThreadSSE());
    }
    

    That is, it won't anymore let you pass additional arguments that would be forwarded to the constructor of AlphaBetaSingleThreadSSE, and instead, will try to use a default constructor of AlphaBetaSingleThreadSSE (which doesn't exist as the error message states).

    You can work around that by specifying also type template parameter Args:

    std::make_unique<AlphaBetaSingleThreadSSE, const int&, const int&>
    

    but then you won't benefit from perfect-forwarding and this is not a portable solultion anyway. A better solution is to stay with a lambda.