C++ 具有不同类型算术的嵌套可变模板参数的构造函数

C++ 具有不同类型算术的嵌套可变模板参数的构造函数,c++,constructor,c++14,variadic-templates,sfinae,C++,Constructor,C++14,Variadic Templates,Sfinae,后续行动 问题 我有一个Matrix的课程,可以做一些数学题。但这纯粹是关于初始化 矩阵 //辅助函数 模板 std::array to_array_impl(常量T(&arr)[N],std::index_序列){ 返回std::数组{arr[Is]…}; } 模板 std::数组到_数组(常量T(&arr)[N]){ 返回到_数组_impl(arr,std::make_index_sequence{}); } //母体 模板 类矩阵{ 公众: 模板 矩阵(TArgs const(&&…行)[

后续行动

问题 我有一个
Matrix
的课程,可以做一些数学题。但这纯粹是关于初始化

矩阵

//辅助函数
模板
std::array to_array_impl(常量T(&arr)[N],std::index_序列){
返回std::数组{arr[Is]…};
}
模板
std::数组到_数组(常量T(&arr)[N]){
返回到_数组_impl(arr,std::make_index_sequence{});
}
//母体
模板
类矩阵{
公众:
模板
矩阵(TArgs const(&&…行)[M]):数据{to_数组(行)…}{
// ...
私人:

std::array data;//这里的主要问题是,当初始值设定项列表的内容是异构的时,它无法推断类型,因此
{1,2,3.F}
将不起作用。第二个问题是,即使指定了类型,如果存在隐式缩小转换(例如,
double
->
int
),也会出现编译器错误

我们必须以某种方式将异构初始值设定项列表转换为一个同质集合

方法#1 制作一个小助手函数,将参数转换为适当的
std::array

这是我们最容易理解的类型。我们可以使用
tuple
,但这更轻,因为我们实际上没有携带任何值

2.
唯一类型列表
,它将从
类型列表
转换为唯一类型的
类型列表
这是一个需要额外样板的棘手问题:

  • 一种检测类型
    是否出现在可变类型列表
    尾中的方法…
为此,我们将结合使用
std::disconction
std::same_作为
来执行此检测(注意:您可能希望在完全功能的impl中删除CVREF):

现在,在的帮助下,我们可以构建一组独特的类型:

template<class... T>
struct unique_typelist
{
    using type = typelist<>;
};

template<class Head, class... Tail>
struct unique_typelist<Head, Tail...>
{
    using type = std::conditional_t<is_present<Head, Tail...>::value,
         typename unique_typelist<Tail...>::type, // if condition is true
          typename concat<typelist<Head>, typename unique_typelist<Tail...>::type>::type>;
};
最好自下而上阅读: 给定一些可能重复的类型集,
T.
,我们:

  • T..
    转换为
    typelist
    ,其中每个
    U
    都是唯一的,然后
  • 类型列表
    零件从
    U.
    中剥离出来,放入
    std::variant
4.创建一个std::arraystd::variant,给定一组类型为T的参数。。。 考虑到我刚才给你们讲的,这是相当简单的:

template<class... T>
constexpr auto make_variant_array(T&&... args) -> std::array<variant_from_types_t<T...>, sizeof...(T)>
{
    return {std::forward<T>(args)...};
};
is\u variant\u array
提出问题“is
T
一个大小为
N
的数组,其中每个元素都是
std::variant
?”

让我们在我们的
矩阵
构造函数中看到它的作用:

template<class... Ts, std::enable_if_t<sizeof...(Ts) == N && (std::is_same_v<Ts, std::array<T, M>> && ...), int> = 0>
Matrix(Ts&&... args) : data{std::forward<Ts>(args)...}
{
}
template <std::size_t N, std::size_t M, typename T>
class Matrix{
  public:
    template<class... Ts, std::enable_if_t<sizeof...(Ts) == N && (is_variant_array<M, Ts>::value && ...), int> = 0>
    Matrix(Ts&&... args)
{ /*...*/}
然后,我们将在构造函数中使用它,并使用一个小技巧I(我们?)调用简单扩展,该扩展涉及一个废弃的值表达式和一个逗号运算符来强制排序:

cast_visitor<T> visitor;
std::size_t i = 0;
auto add_row = [&, this](auto varray)
{
   for(size_t j = 0; j < M; ++j)    
   {
       data[i][j] = std::visit(visitor, varray[j]);
   }
};
    
using swallow = size_t[];
(void)swallow{(void(add_row(args)), ++i)...};
cast_访客;
标准:尺寸i=0;
自动添加_行=[&,this](自动varray)
{
对于(尺寸j=0;j
7.最后,我们准备好调用我们的构造函数了!
矩阵m{make_variant_array(1,2,3),make_variant_array(4,5,6)};
这并不漂亮,但它完成了任务


这里的主要问题是,当初始值设定项列表的内容是异构的时,它无法推断类型,因此
{1,2,3.F}
将不起作用。第二个问题是,即使指定了类型,如果存在隐式缩小转换(例如,
double
->
int
),也会出现编译器错误

我们必须以某种方式将异构初始值设定项列表转换为一个同质集合

方法#1 制作一个小助手函数,将参数转换为适当的
std::array

这是我们最容易理解的类型。我们可以使用
tuple
,但这更轻,因为我们实际上没有携带任何值

2.
唯一类型列表
,它将从
类型列表
转换为唯一类型的
类型列表
这是一个需要额外样板的棘手问题:

  • 一种检测类型
    是否出现在可变类型列表
    尾中的方法…
为此,我们将结合使用
std::disconction
std::same_作为
来执行此检测(注意:您可能希望在完全功能的impl中删除CVREF):

现在,在的帮助下,我们可以构建一组独特的类型:

template<class... T>
struct unique_typelist
{
    using type = typelist<>;
};

template<class Head, class... Tail>
struct unique_typelist<Head, Tail...>
{
    using type = std::conditional_t<is_present<Head, Tail...>::value,
         typename unique_typelist<Tail...>::type, // if condition is true
          typename concat<typelist<Head>, typename unique_typelist<Tail...>::type>::type>;
};
最好自下而上阅读: 给定一些可能重复的类型集,
T.
,我们:

  • T..
    转换为
    typelist
    ,其中每个
    U
    都是唯一的,然后
  • 类型列表
    零件从
    U.
    中剥离出来,放入
    std::variant
4.创建一个std::arraystd::variant,给定一组类型为T的参数。。。 考虑到我刚才给你们讲的,这是相当简单的:

template<class... T>
constexpr auto make_variant_array(T&&... args) -> std::array<variant_from_types_t<T...>, sizeof...(T)>
{
    return {std::forward<T>(args)...};
};
is\u variant\u array
提出问题“is
T
一个大小为
N
的数组,其中每个元素都是
std::variant
?”

让我们在我们的
矩阵
构造函数中看到它的作用:

template<class... Ts, std::enable_if_t<sizeof...(Ts) == N && (std::is_same_v<Ts, std::array<T, M>> && ...), int> = 0>
Matrix(Ts&&... args) : data{std::forward<Ts>(args)...}
{
}
template <std::size_t N, std::size_t M, typename T>
class Matrix{
  public:
    template<class... Ts, std::enable_if_t<sizeof...(Ts) == N && (is_variant_array<M, Ts>::value && ...), int> = 0>
    Matrix(Ts&&... args)
{ /*...*/}
然后,我们将在构造函数中使用它,并使用一个小技巧I(我们?)调用简单扩展,该扩展涉及一个废弃的值表达式和一个逗号运算符来强制排序:

cast_visitor<T> visitor;
std::size_t i = 0;
auto add_row = [&, this](auto varray)
{
   for(size_t j = 0; j < M; ++j)    
   {
       data[i][j] = std::visit(visitor, varray[j]);
   }
};
    
using swallow = size_t[];
(void)swallow{(void(add_row(args)), ++i)...};
cast_访客;
标准:尺寸i=0;
自动添加_行=[&,this](自动varray)
{
对于(尺寸j=0;j
7.最后,我们准备好调用我们的构造函数了!
矩阵m{make_variant_array(1,2,3),make_variant_array(4,5,6)};
这并不漂亮,但它完成了任务

“在那
template<class...>
struct typelist_to_variant;

template<class... T>
struct typelist_to_variant<typelist<T...>>
{
    using type = std::variant<T...>;
};

template<class...>
struct unique_typelist_to_variant;

template<class... T>
struct unique_typelist_to_variant<unique_typelist<T...>>
{
    using type = typename typelist_to_variant<typename unique_typelist<T...>::type>::type;
};

template<class... T>
struct variant_from_types
{
    using type = typename unique_typelist_to_variant<unique_typelist<T...>>::type;
};

template <class... T>
using variant_from_types_t = typename variant_from_types<T...>::type; 
template<class... T>
constexpr auto make_variant_array(T&&... args) -> std::array<variant_from_types_t<T...>, sizeof...(T)>
{
    return {std::forward<T>(args)...};
};
template<size_t N, class T>
struct is_variant_array : std::false_type{};

template<size_t N, class... T>
struct is_variant_array<N, std::array<std::variant<T...>, N>> : std::true_type{};
template <std::size_t N, std::size_t M, typename T>
class Matrix{
  public:
    template<class... Ts, std::enable_if_t<sizeof...(Ts) == N && (is_variant_array<M, Ts>::value && ...), int> = 0>
    Matrix(Ts&&... args)
{ /*...*/}
template<class T>
struct cast_visitor
{
    template<class U>
    T operator()(U u) const
    {
        return static_cast<T>(u);
    }
};
cast_visitor<T> visitor;
std::size_t i = 0;
auto add_row = [&, this](auto varray)
{
   for(size_t j = 0; j < M; ++j)    
   {
       data[i][j] = std::visit(visitor, varray[j]);
   }
};
    
using swallow = size_t[];
(void)swallow{(void(add_row(args)), ++i)...};
Matrix<2,3,int> m{ make_variant_array(1,2,3), make_variant_array(4,5,6)};