使用左值引用错误地调用了Rvalue引用构造函数

Rvalue reference constructor incorrectly called with an lvalue reference

本文关键字:引用 调用 Rvalue 构造函数 错误      更新时间:2023-10-16

编译此代码时:

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;
}

我收到编译器的消息:

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

看起来C ca(base);与右值引用ctor调用相关联。为什么编译器很难将这一行与第一个ctor关联起来?如果我注释掉有问题的行,那么cccd的构造就如预期的那样工作。

如果要复制移动,请按值传递。以一种简化的方式:

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

否则,如果您有一个像template <typename T> ... T &&这样的通用引用,则可以将基类型获取为typename std::decay<T>::type(来自<type_traits>)。在这种情况下,您应该将参数作为std::forward<T>(inBase)传递。

重载通用引用是个坏主意(参见Scott Meyer最近的演讲)。

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

这些将调用模板化的通用引用构造函数,因为通用引用绑定到everything,并且由于basederived没有作为const &传入,所以它不会绑定到第一个构造函数。相反,编译器推断模板参数为Base & &&Derived & &&,在引用折叠规则之后,您将得到最终调用错误的Base &Derived &

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

这些工作是因为临时只能绑定到CCD_ 17,因此第一个构造函数是更好的匹配。