C++ 使用左值引用错误地调用了右值引用构造函数

C++ 使用左值引用错误地调用了右值引用构造函数,c++,c++11,rvalue-reference,C++,C++11,Rvalue Reference,当我编译此代码时: 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) : b

当我编译此代码时:

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;
}
类基类{/*…*/};
派生类:公共基{/*…*/};
C类
{
公众:
模板
C(T常量和inBase):baseInC(新T(inBase)){/*…*/}
模板
C(T&&inBase):baseInC(新T(std::move(inBase)){/*…*/}
std::unique_ptr baseInC;
};
int main()
{
基地;
派生的;
C钙(碱);
C cb(衍生);
C cc((Base());
cd((派生的());
返回0;
}
我收到一条编译器消息:

在C::C(T&&)[with T=Base&]'的实例化中:需要来自C-ca(Base);错误:不能将“新建”应用于引用类型

在C::C(T&&)[with T=Derived&]]的实例化中:C cb(Derived)中需要;错误:不能将“新建”应用于引用类型

它看起来像
cca(base)正在与右值引用调用关联。为什么编译器很难将这一行与第一个ctor关联起来?如果我注释掉了有问题的行,
cc
cd
的构造与预期一样有效。

如果您仍要复制或移动,请传递值。以简化的方式:

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

否则,如果您有像
模板这样的通用引用。。。T&
,您可以将基本类型获取为
typename std::decay::type
(从
)。在这种情况下,您应该将参数作为
std::forward(inBase)

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

它们将调用模板化的通用引用构造函数,因为通用引用绑定到所有内容,并且由于
派生的
未作为
常量和
传入,它将不会绑定到第一个构造函数。相反,编译器将模板参数推断为
Base&&&
派生&&&&
,在引用折叠规则之后,您将得到
Base&
派生&
,它们最终调用错误

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

这些方法有效,因为临时方法只能绑定到常量&
,因此第一个构造函数更匹配。

阅读通用引用。这里是书面形式,嗯。不过,这似乎不适用于临时方法。如果我在ctor中放入print语句,那么
ccc((Base())行中不会打印任何内容
cdc((派生的())。啊,没关系。这是MVP的问题。我在问题中加了括号,但在实际代码中没有。哎呀@塞巴斯蒂安·雷迪:为什么这是件好事?我想让代码在本地复制temp。这不是一件非常安全的事情吗?@Fadecomic每当编译器删除一个副本时,这是一件好事。在不安全的情况下,它永远不会这样做。一般来说,当删除临时对象时,这是因为该对象直接在其最终位置构造。
C cc( (Base()) );
C cd( (Derived()) );