编译此代码时:
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相关联?如果我注释掉有问题的行,cc
和cd
的构建将按预期工作。
答案 0 :(得分:5)
如果您要复制或移动,请按值传递。以简化的方式:
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)
。
答案 1 :(得分:0)
超载普遍参考是一个坏主意(参见Scott Meyer最近的演讲)。
C ca(base);
C cb(derived);
这些将调用模板化的通用引用构造函数,因为通用引用绑定到 所有内容 ,并且因为base
和derived
未传入一个const &
,它不会绑定到第一个构造函数。相反,编译器将模板参数推断为Base & &&
和Derived & &&
,并且在引用折叠规则之后,您将获得最终调用错误的Base &
和Derived &
。
C cc( (Base()) );
C cd( (Derived()) );
这些工作因为临时只能绑定到const &
,因此第一个构造函数是更好的匹配。