我想用C ++ 17 boost::variant
替换std::variant
并删除boost::recursive_wrapper
,以便在以下代码中完全消除对boost的依赖。我怎么能这样做?
#include <boost/variant.hpp>
#include <type_traits>
using v = boost::variant<int, boost::recursive_wrapper<struct s> >;
struct s
{
v val;
};
template<template <typename...> class R, typename T, typename ... Ts>
auto reduce(T t, Ts ... /*ts*/)
{
return R<T, Ts...>{t};
}
template<typename T, typename F>
T adapt(F f)
{
static_assert(std::is_convertible_v<F, T>, "");
return f;
}
int main()
{
int val1 = 42;
s val2;
auto val3 = adapt<v>(reduce<boost::variant>(val1, val2));
}
有两个通用函数:第一个函数reduce
在运行时选择返回哪个参数(这里它只是为了简洁而返回第一个参数),第二个函数adapt
将类型F的值转换为一个值类型为T.
在此示例中,reduce
返回boost::variant<int, s>
类型的对象,然后将其转换为boost::variant<int, boost::recursive_wrapper<s> >
类型的对象。
答案 0 :(得分:17)
autoscaler
将堆分配,以便将其自身的一部分递归地定义为自身。 (它还将在许多其他情况下堆积分配,不确定多少)
boost::variant
不会。 std::variant
拒绝堆分配。
如果没有动态分配,就没有办法实际拥有包含自身可能变体的结构,因为如果静态声明,这样的结构可以很容易地显示为无限大小。 (您可以通过N次递归来编码整数N:没有固定大小的缓冲区可以容纳无限量的信息。)
因此,等价的std::variant
存储了一个自身递归实例的某种占位符的智能指针。
这可能有效:
std::variant
如果没有,请尝试:
struct s;
using v = std::variant< int, std::unique_ptr<s> >;
struct s
{
v val;
~s();
};
inline s::~s() = default;
这确实意味着客户端代码必须故意与struct destroy_s;
struct s;
using v = std::variant<int, std::unique_ptr<s, destroy_s> >;
struct s
{
v val;
~s();
};
struct destroy_s {
void operator()(s* ptr){ delete ptr; }
};
inline s::~s() = default;
而不是unique_ptr<s>
直接互动。
如果你想支持复制语义,你必须写一个复制的struct s
,并给它相当于value_ptr
来实现该复制。
struct copy_s;
Live example of value_ptr。