问题描述
我有一个二进制格式,我正在为其编写编码器和解码器。几乎所有的二进制类型都直接映射到基元,除了两个容器类型,一个列表和一个映射类型,它们可以包含格式中的任何其他类型,包括它们自己。
这些感觉就像他们只是想成为 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
的措辞有点错误。我相信这会在未来的标准修订版中得到解决。
无论如何,这会减少一点摩擦。