1
votes

I need to have a class which takes copy/move and a templated constructor like the following example:

    class A
{
    public:
    A() {}
    A( A&& ){std::cout << "Move" << std::endl;}
    A( const A& ){ std::cout << "copy" << std::endl;}

    template < typename T>
        A( T&& ) { std::cout << "any" << std::endl; }
};

class B: public A
{
    public:
    B():A() {}
    B( const B& b): A(b) {}
    B( B&& b): A( std::move(b)) {}
};

int main()
{
    B b;
    B b2( b );              // expected call copy
    B b3( std::move( b ));  // expected call to move

}

But I run into the templated constructor which is absolutely misterious to me. Why is the move constructor not the better match?

Found some hints here: Template Constructor Taking Precedence Over Normal Copy and Move Constructor?

In one of the comments I see that SFINAE is taken a possibility. But I could not see any valid implementation to select the correct constructor. Can someone give me a hint to pick up the correct constructor?

I expect to go up the inheritance hierarchy with the move constructors. So how to implement the move constructors that the correct one of the base class will be chosen. As this I expect the output "move" here instead of "any".

EDIT: In addition to the given answer the following solution seem also to work:

class B: public A
{    
    public:
        B():A() {}
        B( const B& b ): A( (const A&)b ) {}
        D( B&& b): A( std::forward<A>(b)) {}
};

That also explains why the template in the base class "eats" the constructor call, as the implicit cast from B to A is not needed for the template and so the template is the better match. If explicit casted before, all works fine.

1
the one that prints "Move" is not a move-constructor.. please include the output and the expected one, just to avoid misunderstandings - 463035818_is_not_a_number
@formerlyknownas_463035818: quite clear... sorry fixed it - Klaus
And please show us the output you get from running the program, and the output you expect to get. - Some programmer dude
@Klaus dont say sorry to me, but maybe to Nathan, it is his answer that now maybe has to be fixed - 463035818_is_not_a_number

1 Answers

4
votes

In

A( std::move(b))

std::move(b) gives you a B&&. When overload resolution is performed it finds A( A&& ) and (from the template) A( B&& ). The template is an exact match, so it will chose that instead.

To fix this, just get rid of the template, you don't need it. If you do need it in your actual code, then you can use SFINAE on the template constructor to stop it from being called by derived classes using

template < typename T, std::enable_if_t<!std::is_convertible_v<T*, A*>, bool> = true>
A( T&& ) { std::cout << "any" << std::endl; }