[英]templated constructor vs. templated copy constructor
I have a class with a templated constructor for implicit move conversion, however this constructor should NOT be used for the class (which should only be copy constructible). 我有一个带有模板化构造函数的类,用于隐式移动转换,但是这个构造函数不应该用于类(它应该只是可复制的构造)。 However, the compiler always tries to use the templated constructor instead of the regular copy constructor. 但是,编译器总是尝试使用模板化构造函数而不是常规复制构造函数。
eg With this i get the follow compiler errors, link . 例如,我得到以下编译器错误, 链接 。 (you can just copy paste this code if you want to try it) (如果你想试试,可以复制粘贴这段代码)
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_;
};
Any one got an idea how to solve this properly? 任何人都知道如何妥善解决这个问题?
Okay, here is my complete overhaul of my_class
: 好的,这是我对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_;
};
As suggested by others, this works for lvalue and rvalue references by using std::forward
instead of std::move
. 正如其他人所建议的那样,这适用于使用std::forward
而不是std::move
左值和右值引用。 The remove_reference
is necessary because for lvalue references, T
is a reference, and derived&
does not derive from base
, but derived
does (note the reference). remove_reference
是必要的,因为对于左值引用, T
是一个引用, derived&
不是从base
派生的,而是derived
(请注意引用)。
This can never work: 这永远不会奏效:
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)
The reason is that you only use T
in non-deduced contexts. 原因是您只在非推导的上下文中使用T
Plainly speaking, the compiler cannot deduce T
if the argument it should have deduce it from has the form Anything<T>::type
. 简单来说,编译器不能推断T
如果它应该推导出的参数具有Anything<T>::type
。
So, if you want to use enable_if
on assignment operator, you put it in the return value: 因此,如果要在赋值运算符上使用enable_if
,则将其放在返回值中:
template <class T>
typename enable_if<..., T&>::type operator=(const T&);
in case of the conversion (should work for move, too) constructor, you add a dummy parameter with default value: 如果转换(也应该适用于move)构造函数,则添加一个带有默认值的虚拟参数:
template <class T>
MyClass(const T&, typename enable_if<..., void>::type* =0);
FredOverflow already gave you the correct assignment operator. FredOverflow已经为您提供了正确的赋值运算符。
BTW you needn't restrict it to rvalue-references, if you use std::forward
instead of std::move
. 顺便说一句,如果使用std::forward
而不是std::move
,则无需将其限制为rvalue-references。 See here . 看到这里 。 That would give you (copy&paste from FredOverflow): 这会给你(从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;
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.