简体   繁体   中英

Rvalue reference constructor incorrectly called with an lvalue reference

When I compile this code:

class Base { /*...*/ };
class Derived : public Base { /*...*/ };

class C
{
public:
    template<typename T>
    C(T const& inBase) : baseInC(new T(inBase)) { /*...*/ }

    template<typename T>
    C(T&& inBase) : baseInC(new T(std::move(inBase))) { /*...*/ }

    std::unique_ptr<Base> baseInC;
};

int main()
{
    Base base;
    Derived derived;

    C ca(base);
    C cb(derived);

    C cc( (Base()) );
    C cd( (Derived()) );

    return 0;
}

I get a the compiler message:

In instantiation of C::C(T&&) [with T = Base&]': required from C ca(base); error: new cannot be applied to a reference type

In instantiation of C::C(T&&) [with T = Derived&]': required from C cb(derived); error: new cannot be applied to a reference type

It looks like C ca(base); is being associated with the rvalue reference ctor call. Why is the compiler having difficulty associating this line with the first ctor? The construction of cc and cd works as expected if I comment out the offending lines.

If you're going to copy or move anyway, pass by value. In a simplified way:

template <typename T>
void foo(T x)
{
    T * p = new T(std::move(x));
}

Otherwise, if you have a universal reference like template <typename T> ... T && , you can get the base type as typename std::decay<T>::type (from <type_traits> ). In that case, you should pass the argument as std::forward<T>(inBase) .

overloading on universal reference is a bad idea( see Scott Meyer's recent talk ).

C ca(base);
C cb(derived);

these will call the templated universal reference constructor because universal reference binds to everything , and since base and derived is not passed in as a const & , it will not bind to the first constructor. Instead the compiler deduced the template argument to be Base & && and Derived & && and after reference collapsing rule you get Base & and Derived & which ultimately invoke the error.

C cc( (Base()) );
C cd( (Derived()) );

these work because temporary can only bind to const & thus the first constructor is a better match.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM