我可以在C++中扩展变体吗?
Can I extend variant in C++?
我不确定这是否可能,但说我有:
using my_variant = std::variant<Class1, Class2, Class3>;
现在在某个时候,我创建了一个Class4
,并希望扩展my_variant2
以包含所有my_variant
以及Class4
(以一般方式,即不只是使用另一个using...
(,以便我可以做一些事情,例如创建一个数组std::array<my_variant2, n>
。
这是可以做到的吗?
godbolted
#include <variant>
template <typename T, typename... Args> struct concatenator;
template <typename... Args0, typename... Args1>
struct concatenator<std::variant<Args0...>, Args1...> {
using type = std::variant<Args0..., Args1...>;
};
int main() {
using type_t = std::variant<int, char, double>;
static_assert(
std::is_same_v<
concatenator<type_t, float, short>::type,
std::variant<int, char, double, float, short>>);
return 0;
}
实现此目的有两个步骤。第一种是标识原始std::variant
中使用的类型列表,第二种是使用原始参数加上要添加的参数构造新的std::variant
类型。
部分模板专用化可用于编写一个特征,该特征将获取给定std::variant
中使用的模板类型列表:
#include <variant>
template<class T>
struct t_variant_cat;
template<class ... Old>
struct t_variant_cat<std::variant<Old...>> {
// Old is a parameter pack containing all of
// template arguments of the std::variant
};
接下来,我们添加另一个模板参数,该参数指定要添加的类型并为此新类型定义别名。
#include <variant>
template<class T, class New>
struct t_variant_cat;
template<class ... Old, class New>
struct t_variant_cat<std::variant<Old...>, New> {
using type = std::variant<Old..., New>;
};
typename t_variant_cat<my_variant, Class4>::type
现在应该产生std::variant<Class1, Class2, Class3, Class4>
.为了方便起见,我们可以添加一个类型别名,以避免每次都写入typename
和::type
:
template<class Old, class New>
using t_variant_cat_t = typename t_variant_cat<Old, New>::type;
用法是:
#include <variant>
template<class T, class New>
struct t_variant_cat;
template<class ... Old, class New>
struct t_variant_cat<std::variant<Old...>, New> {
using type = std::variant<Old..., New>;
};
template<class Old, class New>
using t_variant_cat_t = typename t_variant_cat<Old, New>::type;
using old = std::variant<int, float>;
using extended = t_variant_cat_t<old, double>;
// Makes sure this actually works
static_assert(std::is_same_v<extended, std::variant<int, float, double>>,
"Something is wrong.");
namespace impl_details {
template<class Var, class...Ts>
struct extend_type;
template<template<class...>class Z, class...Vs, class...Ts>
struct extend_type<Z<Vs...>, Ts...> {
using type=Z<Vs..., Ts...>;
};
}
template<class Var, class...Ts>
using extend_type = typename impl_details::extend_type<Var, Ts...>::type;
现在
extend_type<my_variant, Class4>
是
std::variant<Class1, Class2, Class3, Class4>
虽然我不赞成你基于 1 的索引。
extend_type< std::tuple<a,b,c>, d, e, f >
也有效。
我可以从中获得一些乐趣...
namespace impl_details {
template<class Lhs, class Rhs>
struct type_cat;
template<template<class...>class Z, class...Lhs, class...Rhs>
struct type_cat<Z<Lhs...>, Z<Rhs...>> {
using type=Z<Lhs..., Rhs...>;
};
}
template<class Lhs, class Rhs>
using type_cat = typename impl_details::type_cat<Lhs, Rhs>::type;
auto variant_trinary( bool b ) {
return [b](auto&& lhs, auto&& rhs) {
using R=type_cat< std::decay_t<decltype(lhs)>, std::decay_t<decltype(rhs)> >;
auto as_R = [](auto&&x)->R{ return decltype(x)(x)); };
if (b)
return std::visit( as_R, lhs );
else
return std::visit( as_R, rhs );
};
}
这给了我们两个变体的三位一体运算符。
auto var = variant_trinary(bool_expr)( var1, var2 );
其中var
是var1
和var2
变体类型的连接。
bobah 在这里的回答非常有帮助,但我不清楚如何处理其中的运行时部分,以及如何在运行时实际合并这些对象。
显然,一个大的if链是一种选择,但实际上有一种不同的,更简洁的方法可以做到这一点:
#include <iostream>
#include <variant>
template <typename T, typename... Args> struct concatenator;
template <typename... Args0, typename... Args1>
struct concatenator<std::variant<Args0...>, Args1...> {
using type = std::variant<Args0..., Args1...>;
};
int main() {
using typea_t = std::variant<int, char, double>;
using typeb_t = concatenator<typea_t, float, short>::type;
float foo = 0.1f;
typea_t bar{12.0};
typeb_t foobar = foo;
std::visit([&](auto&& value) { foobar = value; }, bar);
std::visit([](auto&& value) { std::cout << value << std::endl; }, foobar);
return 0;
}
戈德博尔特
- 是否可以通过C++扩展强制多个python进程共享同一内存
- static_assert在宏中,但也可以扩展到可以用作函数参数的东西
- 如何将这个C++哈希表转换为动态扩展和收缩,而不是使用硬设置的最大值
- 扩展光电二极管探测器以支持多个传感器
- C++中的VLA,扩展名为std=C++11
- OpenGL 和 GLM 矩阵无法正确扩展,总是按比例缩小
- 基于范围的 for 循环:迭代使用一个元素扩展的向量
- C++返回 Numpy 数组的 Python 扩展模块
- 扩展可变参数模板中的变量名称
- 扩展C++生成的代码的模板参数类型名称
- 我想通过带有C++和Python的插件创建一个可扩展的应用程序
- VSCode IntelliSense无法识别SDL框架的SDL_image扩展库
- 将元组类型扩展为可变参数模板?
- 如何按文件扩展名引用文件夹中的文件
- HDF5Cpp 扩展复合数据集超板问题
- MSVC中的宏观扩展问题
- 嵌套参数包扩展失败
- C4204:使用的非标准扩展:非常量聚合初始值设定项
- [temp.variadic]中关于包扩展实例化的措辞
- 我应该包含什么来制作 boost.python 扩展?