<tfoot id='e4diX'></tfoot>
    1. <legend id='e4diX'><style id='e4diX'><dir id='e4diX'><q id='e4diX'></q></dir></style></legend>

      <small id='e4diX'></small><noframes id='e4diX'>

        <bdo id='e4diX'></bdo><ul id='e4diX'></ul>

      1. <i id='e4diX'><tr id='e4diX'><dt id='e4diX'><q id='e4diX'><span id='e4diX'><b id='e4diX'><form id='e4diX'><ins id='e4diX'></ins><ul id='e4diX'></ul><sub id='e4diX'></sub></form><legend id='e4diX'></legend><bdo id='e4diX'><pre id='e4diX'><center id='e4diX'></center></pre></bdo></b><th id='e4diX'></th></span></q></dt></tr></i><div id='e4diX'><tfoot id='e4diX'></tfoot><dl id='e4diX'><fieldset id='e4diX'></fieldset></dl></div>

        将 std::variant 与递归一起使用,而不使用 boost::recursive_wrapper

        时间:2023-07-20

        <legend id='Ihj07'><style id='Ihj07'><dir id='Ihj07'><q id='Ihj07'></q></dir></style></legend>
        <i id='Ihj07'><tr id='Ihj07'><dt id='Ihj07'><q id='Ihj07'><span id='Ihj07'><b id='Ihj07'><form id='Ihj07'><ins id='Ihj07'></ins><ul id='Ihj07'></ul><sub id='Ihj07'></sub></form><legend id='Ihj07'></legend><bdo id='Ihj07'><pre id='Ihj07'><center id='Ihj07'></center></pre></bdo></b><th id='Ihj07'></th></span></q></dt></tr></i><div id='Ihj07'><tfoot id='Ihj07'></tfoot><dl id='Ihj07'><fieldset id='Ihj07'></fieldset></dl></div>
        • <bdo id='Ihj07'></bdo><ul id='Ihj07'></ul>
          • <tfoot id='Ihj07'></tfoot>

              1. <small id='Ihj07'></small><noframes id='Ihj07'>

                    <tbody id='Ihj07'></tbody>
                  本文介绍了将 std::variant 与递归一起使用,而不使用 boost::recursive_wrapper的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着跟版网的小编来一起学习吧!

                  问题描述

                  我想用 C++17 std::variant 替换 boost::variant 并去掉 boost::recursive_wrappercode>,在下面的代码中完全消除对boost的依赖.我该怎么做?

                  I'd like to replace boost::variants with C++17 std::variant and get rid of boost::recursive_wrapper, to remove dependency on boost completely in following code. How may I do that?

                  #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 的值.

                  There are two generic functions: first function reduce chooses at runtime which argument to return (here it just returns first argument for brevity), second function adapt converts a value of type F to a value of type T.

                  在这个例子中,reduce 返回一个 boost::variant 类型的对象,然后它被转换成一个 boost:: 类型的对象变体<int, boost::recursive_wrapper<s>>.

                  In this example reduce returns an object of type boost::variant<int, s> which is then converted to an object of type boost::variant<int, boost::recursive_wrapper<s> >.

                  推荐答案

                  boost::variant 将堆分配以便将自身的一部分递归地定义为自身.(它也会在其他一些情况下堆分配,不知道有多少)

                  boost::variant will heap allocate in order to have part of itself be recursively defined as itself. (It will also heap allocate in a number of other situations, uncertain how many)

                  std::variant 不会.std::variant 拒绝堆分配.

                  std::variant will not. std::variant refuses to heap allocate.

                  在没有动态分配的情况下,没有办法真正拥有包含自身可能变体的结构,因为如果静态声明,这样的结构很容易显示为无限大.(您可以通过 N 个不相同的递归来编码整数 N:没有固定大小的缓冲区可以容纳无限量的信息.)

                  There is no way to actually have a structure containing a possible variant of itself without a dynamic allocation, as such a structure can easily be shown to be infinite in size if statically declared. (You can encode the integer N by having N recursions of not-the-same: no fixed size buffer can hold an infinite amount of information.)

                  因此,等效的 std::variant 存储了一个智能指针,它是自身递归实例的某种占位符.

                  As such, the equivalent std::variant stores a smart pointer of some kind placeholder of a recursive instance of itself.

                  这可能有效:

                  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 而不是 struct s 直接交互.

                  It does mean that client code has to knowingly interact with the unique_ptr<s> and not the struct s directly.

                  如果你想支持复制语义,你必须编写一个执行复制的 value_ptr,并赋予它等效的 struct copy_s; 来实现该复制.

                  If you want to support copy semantics, you'll have to write a value_ptr that does copies, and give it the equivalent of struct copy_s; to implement that copy.

                  template<class T>
                  struct default_copier {
                    // a copier must handle a null T const* in and return null:
                    T* operator()(T const* tin)const {
                      if (!tin) return nullptr;
                      return new T(*tin);
                    }
                    void operator()(void* dest, T const* tin)const {
                      if (!tin) return;
                      return new(dest) T(*tin);
                    }
                  };
                  template<class T, class Copier=default_copier<T>, class Deleter=std::default_delete<T>,
                    class Base=std::unique_ptr<T, Deleter>
                  >
                  struct value_ptr:Base, private Copier {
                    using copier_type=Copier;
                    // also typedefs from unique_ptr
                  
                    using Base::Base;
                  
                    value_ptr( T const& t ):
                      Base( std::make_unique<T>(t) ),
                      Copier()
                    {}
                    value_ptr( T && t ):
                      Base( std::make_unique<T>(std::move(t)) ),
                      Copier()
                    {}
                    // almost-never-empty:
                    value_ptr():
                      Base( std::make_unique<T>() ),
                      Copier()
                    {}
                  
                    value_ptr( Base b, Copier c={} ):
                      Base(std::move(b)),
                      Copier(std::move(c))
                    {}
                  
                    Copier const& get_copier() const {
                      return *this;
                    }
                  
                    value_ptr clone() const {
                      return {
                        Base(
                          get_copier()(this->get()),
                          this->get_deleter()
                        ),
                        get_copier()
                      };
                    }
                    value_ptr(value_ptr&&)=default;
                    value_ptr& operator=(value_ptr&&)=default;
                  
                    value_ptr(value_ptr const& o):value_ptr(o.clone()) {}
                    value_ptr& operator=(value_ptr const&o) {
                      if (o && *this) {
                        // if we are both non-null, assign contents:
                        **this = *o;
                      } else {
                        // otherwise, assign a clone (which could itself be null):
                        *this = o.clone();
                      }
                      return *this;
                    }
                    value_ptr& operator=( T const& t ) {
                      if (*this) {
                        **this = t;
                      } else {
                        *this = value_ptr(t);
                      }
                      return *this;
                    }
                    value_ptr& operator=( T && t ) {
                      if (*this) {
                        **this = std::move(t);
                      } else {
                        *this = value_ptr(std::move(t));
                      }
                      return *this;
                    }
                    T& get() { return **this; }
                    T const& get() const { return **this; }
                    T* get_pointer() {
                      if (!*this) return nullptr;
                      return std::addressof(get());
                    }
                    T const* get_pointer() const {
                      if (!*this) return nullptr;
                      return std::addressof(get());
                    }
                    // operator-> from unique_ptr
                  };
                  template<class T, class...Args>
                  value_ptr<T> make_value_ptr( Args&&... args ) {
                    return {std::make_unique<T>(std::forward<Args>(args)...)};
                  }
                  

                  value_ptr 的实例.

                  这篇关于将 std::variant 与递归一起使用,而不使用 boost::recursive_wrapper的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持跟版网!

                      <tbody id='gzzOn'></tbody>

                    <small id='gzzOn'></small><noframes id='gzzOn'>

                  1. <legend id='gzzOn'><style id='gzzOn'><dir id='gzzOn'><q id='gzzOn'></q></dir></style></legend>

                      • <bdo id='gzzOn'></bdo><ul id='gzzOn'></ul>
                        • <i id='gzzOn'><tr id='gzzOn'><dt id='gzzOn'><q id='gzzOn'><span id='gzzOn'><b id='gzzOn'><form id='gzzOn'><ins id='gzzOn'></ins><ul id='gzzOn'></ul><sub id='gzzOn'></sub></form><legend id='gzzOn'></legend><bdo id='gzzOn'><pre id='gzzOn'><center id='gzzOn'></center></pre></bdo></b><th id='gzzOn'></th></span></q></dt></tr></i><div id='gzzOn'><tfoot id='gzzOn'></tfoot><dl id='gzzOn'><fieldset id='gzzOn'></fieldset></dl></div>
                          <tfoot id='gzzOn'></tfoot>