使用带递归的std :: variant,而不使用boost :: recursive_wrapper

时间:2016-09-12 15:56:45

标签: c++ boost c++17

我想用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> >类型的对象。

1 个答案:

答案 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。