Seb*_*ian 9 c++ templates template-meta-programming c++17
我不确定这是可能的,但我说:
using my_variant = std::variant<Class1, Class2, Class3>;
现在,在某些时候,我创建了一个Class4,想扩大my_variant2到包括所有的my_variant沿Class4(在一般的方式,即不只是用另一种using...),所以我可以做一些像创建一个数组std::array<my_variant2, n>.
这是可以做到的吗?
Fra*_*eux 10
实现这一目标有两个步骤.第一个是识别原始类型中使用的类型列表,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
};
Run Code Online (Sandbox Code Playgroud)
接下来,我们添加另一个模板参数,该参数指定要添加的类型并为此新类型定义别名.
#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>;
};
Run Code Online (Sandbox Code Playgroud)
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;
Run Code Online (Sandbox Code Playgroud)
用法是:
#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.");
Run Code Online (Sandbox Code Playgroud)
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;
Run Code Online (Sandbox Code Playgroud)
现在
extend_type<my_variant, Class4>
Run Code Online (Sandbox Code Playgroud)
是
std::variant<Class1, Class2, Class3, Class4>
Run Code Online (Sandbox Code Playgroud)
虽然我不同意你的基于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 );
};
}
Run Code Online (Sandbox Code Playgroud)
这给了我们两个变体的三元运算符.
auto var = variant_trinary(bool_expr)( var1, var2 );
Run Code Online (Sandbox Code Playgroud)
这里var是变异类型的concatination var1和var2.
#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;
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
618 次 |
| 最近记录: |