std::variant 个包含自身的容器
std::variant of a container that contains itself
我有一种二进制格式,我正在为其编写编码器和解码器。几乎所有二进制类型都直接映射到基元,除了两种容器类型,一个列表和一个映射类型,它们可以包含格式中的任何其他类型,包括它们自身。
这些感觉就像他们只是想成为 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;
}
这给使用该类型增加了一点摩擦。这些变量实际上没有其他状态来证明封装它们是合理的。
打出来我意识到我在问“你能转发声明一个模板吗?”这似乎是一个愚蠢的问题。尽管如此,有人对此有更好的策略吗?
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
措辞有点错误。我相信这将在未来的标准修订中得到解决。
无论如何,这会减少一些摩擦。
我有一种二进制格式,我正在为其编写编码器和解码器。几乎所有二进制类型都直接映射到基元,除了两种容器类型,一个列表和一个映射类型,它们可以包含格式中的任何其他类型,包括它们自身。
这些感觉就像他们只是想成为 std::variant
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;
}
这给使用该类型增加了一点摩擦。这些变量实际上没有其他状态来证明封装它们是合理的。
打出来我意识到我在问“你能转发声明一个模板吗?”这似乎是一个愚蠢的问题。尽管如此,有人对此有更好的策略吗?
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
措辞有点错误。我相信这将在未来的标准修订中得到解决。
无论如何,这会减少一些摩擦。