我有一个带有模板化构造函数的类,用于隐式移动转换,但是这个构造函数不应该用于类(它应该只是可复制的构造)。但是,编译器总是尝试使用模板化构造函数而不是常规复制构造函数。
e.g。有了这个,我得到了以下编译器错误,link。 (如果你想尝试,你可以复制粘贴这段代码)
struct implementation{};
class my_class
{
my_class(my_class&&); // delete move-constructor... OUCH... COMPILER ERROR
public:
my_class(){}
my_class(const my_class& other) : impl_(other.impl_){}
template<typename T>
my_class(T&& impl) : impl_(std::make_shared<T>(std::move(impl))){} // Still tries to use this...
private:
std::shared_ptr<implementation> impl_;
};
class other_class
{
public:
my_class foo()
{
return instance_; // Wants to use move-constructor???
}
private:
my_class instance_;
};
任何人都知道如何妥善解决这个问题?
答案 0 :(得分:4)
好的,这是我对my_class
的全面改革:
class my_class
{
public:
my_class() {}
my_class(my_class&& that) : impl_(std::move(that.impl_)) {}
template <typename T> my_class(T&& impl,
typename std::enable_if<
std::is_base_of<
implementation,
typename std::remove_reference<T>::type
>::value,
void
>::type* dummy = 0
) : impl_(std::make_shared<T>(std::forward<T>(impl))) {}
template <typename T>
typename std::enable_if<
std::is_base_of<
implementation,
typename std::remove_reference<T>::type
>::value,
my_class&
>::type
operator=(T&& impl)
{
std::make_shared<implementation>(std::forward<T>(impl)).swap(impl_);
return *this;
}
private:
std::shared_ptr<implementation> impl_;
};
正如其他人所建议的那样,这适用于使用std::forward
代替std::move
的左值和右值引用。 remove_reference
是必要的,因为对于左值引用,T
是引用,而derived&
不是来自base
,而是derived
({注释引用)
答案 1 :(得分:2)
这永远不会奏效:
template<typename T>
my_class(typename std::enable_if<std::is_base_of<implementation, derived_1>::value, T&&>::type impl) : impl_(std::make_shared<T>(std::move(impl))) {}
template <typename T>
my_class& operator= (typename std::enable_if<std::is_rvalue_reference<T&&>::value && !std::is_same<T, my_class>::value, T&&>::type impl)
原因是您只在非推断的上下文中使用T
。简单来说,编译器不能推导出T
,如果它应该从中推导出它的形式为Anything<T>::type
。
所以,如果你想在赋值运算符上使用enable_if
,你可以把它放在返回值中:
template <class T>
typename enable_if<..., T&>::type operator=(const T&);
如果转换(也适用于移动)构造函数,则添加一个带默认值的虚拟参数:
template <class T>
MyClass(const T&, typename enable_if<..., void>::type* =0);
FredOverflow已经为您提供了正确的赋值运算符。
顺便说一下,如果您使用std::forward
而不是std::move
,则无需将其限制为右值参考。见here。这会给你(从FredOverflow复制和粘贴):
template <typename T>
typename std::enable_if<std::is_base_of<implementation, T>::value, my_class&>::type
operator=(T&& impl)
{
std::make_shared<implementation>(std::forward<T>(impl)).swap(impl_);
return *this;
}