C++ 创建具有扩展索引序列的结构

C++ 创建具有扩展索引序列的结构,c++,c++17,variadic-templates,template-meta-programming,index-sequence,C++,C++17,Variadic Templates,Template Meta Programming,Index Sequence,我希望能够在构造函数的初始值设定项列表中使用参数包扩展。为我的类赋予一个参数包模板参数是实现这一点的最佳方法吗?以下是我的意思的一个例子: #包括 #包括 模板 结构基向量 { constexpr static std::size\u t N=sizeof…(Is); te[N]; base_vec():e{}{} 显式基向量(const T&s):e{((void)Is,s)…}{} }; 模板 std::ostream&operator您可以将扩展完全移动到类内部: template<

我希望能够在构造函数的初始值设定项列表中使用参数包扩展。为我的类赋予一个参数包模板参数是实现这一点的最佳方法吗?以下是我的意思的一个例子:

#包括
#包括
模板
结构基向量
{
constexpr static std::size\u t N=sizeof…(Is);
te[N];
base_vec():e{}{}
显式基向量(const T&s):e{((void)Is,s)…}{}
};
模板

std::ostream&operator您可以将扩展完全移动到类内部:

template<typename T, std::size_t N>
struct vec
{
public:
    T e[N];
    vec() : e{} {}
    explicit vec(const T& s) : vec{s, std::make_index_sequence<N>{}} {}
private:
    template <std::size_t ... Is>
    vec(const T& s, std::index_sequence<Is...>) : e{(Is, s)...} {}
};
模板
结构向量
{
公众:
te[N];
vec():e{}{}
显式vec(const T&s):vec{s,std::make_index_sequence{}}{
私人:
模板
vec(const T&s,std::index_序列):e{(Is,s)…}{}
};

在我看来,您正在重新创建一个受
std::array
启发的类,该类使用一个方便的索引序列进行操作

很有趣

我提出了一种简化(IMHO),使用模板专门化直接定义
vec
,避免
base\u-vec

#include <utility>
#include <iostream>

template <typename T, std::size_t N, typename = std::make_index_sequence<N>>
struct vec;

template <typename T, std::size_t N, std::size_t...Is>
struct vec<T, N, std::index_sequence<Is...>>
 {
    T e[N] {} ;

    vec (const T& s) : e{((void)Is,s)...}
     { }
 };


template <typename T, std::size_t...Is>
std::ostream& operator<< (
   std::ostream& lhs,
   vec<T, sizeof...(Is), std::index_sequence<Is...>> const & rhs)
 { return (std::cout << ... << rhs.e[Is]); }

int main ()
 {
    vec<int, 3u> v(2);

    std::cout << v << "\n";
 }
为避免“被劫持”使用,请如下所示

static_assert( N == sizeof...(Is) );
vec<int, 5u, std::make_index_sequence<12u>>  bad_vec_1;

它完全取决于您希望
vec
表示什么,您希望它的API是什么样子,以及您希望它如何使用。你所做的似乎是合理的。。。假设您想要类似于
std::array
@lightxbulb的东西,您可以始终在类的构造函数中的成员数组上使用
std::fill
std::begin
std::end
。@PetokLorand
std::fill
不是编译时间。这假设
T
是默认值可构造。@PetokLorand:添加缺少的
constexpr
,操作代码也应该是
constexpr
,但在C++20中应该是
constexpr
。所以不管怎么说,这是一个错误的论点。实际上我以前写过完全相同的版本!但我不确定哪一个更好。我在这里编写的版本允许在不使用额外函数的情况下执行此操作,并且该数字会随着其他函数的增加而增加(例如
operator@lightxbulb如果它们是推导出来的,那么它可以。如果您经常需要在编译时迭代数组,那么您也可以提供一个高阶函数来完成这项工作。@lightxbulb:For
operator@Quentin您能详细说明一下吗,因为我遇到了一个错误:
error:parameter pack'Is'必须在模板的末尾e参数列表
。我不确定如何在没有歧义的情况下组合两个非类型参数包。可能是使用虚拟模板?@lightxbulb很难说没有看到您的代码,但这就是我的意思。它确实需要一些跳跃。但是
vec
将部分使用。我最初尝试制作您上面的版本,但是t没有完全正确地编写代码。有没有办法将其扩展到多个索引序列?例如,对于多维数组?编译器将如何区分这两个参数包?一些伪模板会有帮助吗?或者我应该采用嵌套方法?@Jarod42-答案改进以解决这类问题(参见第二个建议的
static_assert()
)@lightxbulb:@lightxbulb-答案在2D案例中得到了改进(但是,我现在看到,在Jarod42演示中几乎是相同的)
static_assert( std::is_same_v<std::index_sequence<Is...>,
                              std::make_index_sequence<N>> );   
vec<int, 5u, std::index_sequence<1u, 3u, 5u, 2u, 4u>>  bad_vec_2;
template <typename T, std::size_t N1, std::size_t N2,
          typename = std::make_index_sequence<N1>,
          typename = std::make_index_sequence<N2>,
          typename = std::make_index_sequence<N1*N2>>
struct vec2dim;

template <typename T, std::size_t N1, std::size_t N2,
          std::size_t ... Is, std::size_t ... Js, std::size_t ... Ks>
struct vec2dim<T, N1, N2, std::index_sequence<Is...>,
               std::index_sequence<Js...>, std::index_sequence<Ks...>>
 {
   static_assert( std::is_same_v<std::index_sequence<Is...>,
                                 std::make_index_sequence<N1>> );
   static_assert( std::is_same_v<std::index_sequence<Js...>,
                                 std::make_index_sequence<N2>> );
   static_assert( std::is_same_v<std::index_sequence<Ks...>,
                                 std::make_index_sequence<N1*N2>> );
   // ...
 };