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
。@PetokLorandstd::fill
不是编译时间。这假设T
是默认值可构造。@PetokLorand:添加缺少的constexpr
,操作代码也应该是constexpr
,但在C++20中应该是constexpr
。所以不管怎么说,这是一个错误的论点。实际上我以前写过完全相同的版本!但我不确定哪一个更好。我在这里编写的版本允许在不使用额外函数的情况下执行此操作,并且该数字会随着其他函数的增加而增加(例如operator@lightxbulb如果它们是推导出来的,那么它可以。如果您经常需要在编译时迭代数组,那么您也可以提供一个高阶函数来完成这项工作。@lightxbulb:Foroperator@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>> );
// ...
};