【问题标题】:std::variant of a container that contains itself包含自身的容器的 std::variant
【发布时间】:2021-08-24 03:44:07
【问题描述】:

我有一个二进制格式,我正在为其编写编码器和解码器。几乎所有二进制类型都直接映射到原语,除了两种容器类型,一个列表和一个映射类型,可以包含格式中的任何其他类型,包括它们自己。

这些感觉就像他们只想成为std::variant的typedef

typedef std::variant<std::vector<char>, std::vector<int>, ...> ListType

但是因为我需要能够包含 ListType 本身的向量,所以我最终会这样做

struct ListType {
  std::variant<std::vector<char>, std::vector<int>, ..., std::vector<ListType>> value;
}

这增加了使用类型的一些摩擦。这些变量确实没有其他状态可以证明封装它们是合理的。

输入它我意识到我在问“你能转发声明一个模板吗?”这似乎是一个愚蠢的问题。不过,有人对此有更好的策略吗?

【问题讨论】:

标签: c++ stl c++17 variant


【解决方案1】:
template<class...Ts>
struct self_variant;

template<class...Ts>
using self_variant_base = 
  std::variant<
    std::vector<Ts>...,
    std::vector<self_variant<Ts...>>
  >;


template<class...Ts>
struct self_variant:
  self_variant_base<Ts...>
{
  using self_variant_base<Ts...>::self_variant_base;
  self_variant_base<Ts...> const& base() const { return *this; }
  self_variant_base<Ts...>& base() { return *this; }
};

template<class T>
void print( T const& t ) {
    std::cout << t << ",";
}
template<class T>
void print( std::vector<T> const& v ) {
    std::cout << "[";
    for (auto const& e:v) {
        print(e);
    }
    std::cout << "]\n";
}
template<class...Ts>
void print( self_variant<Ts...> const& sv ) {
    std::visit( [](auto& e){
        print(e);
    }, sv.base());
}

int main() {
    self_variant<int, char> bob = std::vector<int>{1,2,3};
    self_variant<int, char> alice = std::vector<self_variant<int, char>>{ bob, bob, bob };
    print(alice);
}

所以,.base() 的需要是因为 std::visit 的措辞有点错误。我相信这将在未来的标准修订中得到解决。

无论如何,这会减少一点摩擦。

Live example, 3 recursive depth live example.

【讨论】:

  • 不幸的是,我需要包含仅在运行时才知道的任意嵌套深度的嵌套变体。除非我遗漏了什么,否则这似乎不可能? IE。我可能需要一个装满爱丽丝的爱丽丝,或者一个有交替波波头和爱丽丝的爱丽丝。
  • @nickelpro 这正是这样做的。见godbolt.org/z/f4dW3raMr
  • @nickelpro 要具有任意深度,您需要堆内存。一种简单的方法是拥有一个std::unique_ptr,它可以包含一个变体,如std::unique_ptr&lt;std::variant&lt;int, char&gt;&gt;
  • @Ben 不幸的是,这使得复制类型相当令人沮丧并且代码繁重。我ended up going with the thin wrapper approach 我在问题中列出,因为我需要一个可以与std::map 一起使用的解决方案
  • @nick 我不明白你为什么说复制令人沮丧?默认的 ctor/assign 应该可以工作吗?
猜你喜欢
  • 2020-01-02
  • 1970-01-01
  • 2022-01-22
  • 2013-07-28
  • 2016-11-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多