包含自身的容器的 std::variant

问题描述

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

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

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

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

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

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

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

解决方法

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