boost.variant 派生类型:不能使用复制构造函数
Posted
技术标签:
【中文标题】boost.variant 派生类型:不能使用复制构造函数【英文标题】:boost.variant derived type: cannot use copy constructor 【发布时间】:2017-02-24 11:00:29 【问题描述】:我有一个派生自boost::variant<T, E>
的类型。我做了以下,我不能使用复制构造函数,我不知道为什么,一些SFINAE
似乎失败了。看起来boost::variant<T, E>
构造在继承的构造函数中将T
吞噬为ExpectedResult<T, E>
。
我该如何修复它以使其正常工作并使用最简单的解决方案?
template <class T, class E>
class ExpectedResult : boost::variant<T, E>
public:
using boost::variant<T, E>::variant;
;
ExpectedResult<int,float> er;
ExpectedResult<int, float> er2 = er;
error: no type named 'type' in 'boost::enable_if<boost::mpl::and_<boost::mpl::not_<boost::is_same<Emotiv::Cortex::Utilities::ExpectedResult<int, float>, boost::variant<int, float> > >, boost::detail::variant::is_variant_constructible_from<const Emotiv::Cortex::Utilities::ExpectedResult<int, float> &, boost::mpl::l_item<mpl_::long_<2>, int, boost::mpl::l_item<mpl_::long_<1>, float, boost::mpl::l_end> > >, mpl_::bool_<true>, mpl_::bool_<true>, mpl_::bool_<true> >, void>'; 'enable_if' cannot be used to disable this declaration
typename boost::enable_if<mpl::and_<
^~~~~~~~~~
note: in instantiation of member function 'boost::variant<int, float>::variant' requested here
using boost::variant<T, E>::variant;
while substituting deduced template arguments into function template 'ExpectedResult' [with T = Emotiv::Cortex::Utilities::ExpectedResult<int, float>]
ExpectedResult<int, float> er2 = er;
【问题讨论】:
【参考方案1】:Boost 变体有一个完美的转发构造函数。
您正在将其导入您的班级。
它通过检查self
是否正好是boost::variant
来防止消费self&
。你传递给它一个ExpectedResult&
。
这让人困惑。
template <class T, class E>
struct ExpectedResult : boost::variant<T, E>
using boost::variant<T, E>::variant;
ExpectedResult()=default;
ExpectedResult(ExpectedResult const&)=default;
ExpectedResult(ExpectedResult &&)=default;
ExpectedResult(ExpectedResult & o):
ExpectedResult( const_cast<ExpectedResult const&>(o) )
ExpectedResult(ExpectedResult &&)=default;
ExpectedResult(ExpectedResult const&& o):
ExpectedResult( o ) // calls const& ctor
ExpectedResult& operator=(ExpectedResult const&)=default;
ExpectedResult& operator=(ExpectedResult &&)=default;
ExpectedResult& operator=(ExpectedResult &)
return *this=const_cast<ExpectedResult const&>(o);
ExpectedResult& operator=(ExpectedResult const&& o)
return *this = o; // const& assign
;
我怀疑上述默认和手动编写的特殊成员函数可能会有所帮助。
为了完整起见,您还必须包含 volatile
,将其分解为另一组。
我会小心添加我自己的完美转发构造函数以及使用父构造函数,因为这些更改在 C++17 中如何以可能破坏性的方式发生变化的规则。由于 C++17 中的重大变化,我目前对使用继承的构造函数持怀疑态度,我还没有完全理解。
另一种方法是避免继承构造,而是转发到变体。
template <class T, class E>
struct ExpectedResult : boost::variant<T, E>
using base=boost::variant<T, E>;
ExpectedResult()=default;
ExpectedResult(ExpectedResult const&)=default;
ExpectedResult(ExpectedResult &&)=default;
ExpectedResult(ExpectedResult &&)=default;
ExpectedResult& operator=(ExpectedResult const&)=default;
ExpectedResult& operator=(ExpectedResult &&)=default;
template<class T0, class...Ts,
class=std::enable_if_t<
std::is_constructible<base, T0, Ts...>::value
&& (
(sizeof...(ts)!=0)
|| !std::is_same<std::decay_t<T0>, ExpectedResult>::value
)
>
>
ExpectedResult(T0&&t0, Ts&&...ts):
base(std::forward<T0>(t0), std::forward<Ts>(ts)...)
;
这是一个完美的转发,它有所有的缺陷,但对于大多数用途来说足够接近。
initializer_list<T>, Ts&&...
构造函数可以使完美转发更加完美,所以ExpectedResult<std::vector<int>, bool> er 1,2,3,4
可以工作。
【讨论】:
是否应该将守卫行为视为错误?我发现所有必要的复制都过多。也许我应该提交一个错误。 @GermánDiago 该类型可能不是为了继承而设计的;但他们可以将一些 is_same 更改为 is_base_of 以使其适用于您的情况。我不知道这是否会导致其他问题...以上是关于boost.variant 派生类型:不能使用复制构造函数的主要内容,如果未能解决你的问题,请参考以下文章
boost::variant 中持有的类的复制构造函数的问题
使用 boost::mpl 获取 boost::variant 的类型索引