[英]Initialize array inside variadic template class
I cannot make my head around variadic tempates.我无法绕开可变的模板。 I want to do very simple thing
我想做很简单的事
Tuple t{1,2,3};
should crate tuple of size 3 containing array {1,2,3} ( t.data = {1,2,3}
)应该包含数组 {1,2,3} (
t.data = {1,2,3}
) 的大小为 3 的元组
That means it should do 2 things:这意味着它应该做两件事:
Tuple<T,3>
size 3 ( Tuple<>::data[3]
)Tuple<T,3>
大小 3 ( Tuple<>::data[3]
)Tuple<>::data
with the numbers form std::initializer_listTuple<>::data
This does not work:这不起作用:
template<typename T, T...args>
struct Tuple{
T data[sizeof...(args)];
Tuple(const T& args...):data{args...}{};
};
I tried all sorts of variations like:我尝试了各种变化,例如:
template<typename T, T...args>
//template<typename T, Args...args>
struct Tuple{
T data[sizeof...(args)];
//T data{args...};
//template <typename ...Args>
//Tuple(T... args):data{args...}{};
Tuple(const T& args...):data{args...}{};
//Tuple(T* ...args):data{args...}{};
};
perhaps I don't get difference between T...args
and typename ...Args
and args...
也许我不明白
T...args
和typename ...Args
和args...
I'm trying to use this as simple example to understand variadic templates and avoid using std::initializer_list
我试图将此作为简单示例来理解可变参数模板并避免使用
std::initializer_list
I cannot make my head around variadic tempates.
我无法绕开可变的模板。 I want to do very simple thing
我想做很简单的事
Tuple t{1,2,3};
should crate tuple of size 3 containing
array {1,2,3}
(t.data = {1,2,3}
)应该包含
array {1,2,3}
(t.data = {1,2,3}
) 的大小为 3 的元组
Not sure but, if I understand correctly, your trying to re-create std::array
.不确定,但如果我理解正确,您尝试重新创建
std::array
。
What you want it's impossible before C++17 because your Tuple
it's a template class, so before C++17 you needs to explicit the template arguments.你想要的在 C++17 之前是不可能的,因为你的
Tuple
它是一个模板类,所以在 C++17 之前你需要显式的模板参数。
Starting from C++17, you can use deduction guides.从 C++17 开始,您可以使用演绎指南。
What you want (again: if I understand correctly) is almost the std::array
deduction guide你想要的(再次:如果我理解正确的话)几乎是
std::array
推导指南
template <class T, class... U> array(T, U...) -> array<T, 1 + sizeof...(U)>;
In you case become在你的情况下成为
#include <type_traits>
template <typename T, std::size_t N>
struct Tuple
{
T data[N];
};
template <typename T, typename ... U>
Tuple(T, U...) -> Tuple<T, 1 + sizeof...(U)>;
int main ()
{
Tuple t{1, 2, 3};
static_assert( std::is_same_v<decltype(t), Tuple<int, 3u>> );
}
Observe that a constructor isn't strictly required because the argument are used to initialize the member (the C-style array).请注意,构造函数不是严格要求的,因为参数用于初始化成员(C 样式数组)。
This deduction guide本扣除指南
template <typename T, typename ... U>
Tuple(T, U...) -> Tuple<T, 1 + sizeof...(U)>;
deduce the type of the Tuple::data
array from the first argument and the other argument are used only to deduce the size of the array;从第一个参数推断出
Tuple::data
数组的类型,另一个参数仅用于推断数组的大小; this can be a problem if the types of the arguments are different;如果参数的类型不同,这可能是一个问题; by example
举例
Tuple t1{1l, 2, 3}; // become Tuple<long, 3u>
Tuple t2{2, 2l, 3}; // become Tuple<int, 3u>
Take also in count that, for std::array
还要考虑一下,对于
std::array
The program is ill-formed if
(std::is_same_v<T, U> && ...)
is nottrue
如果
(std::is_same_v<T, U> && ...)
不为true
,则程序格式错误
To solve this problem and have something more flexible, you can use std::common_type_t
, as suggested in other answers, so deduction guide become为了解决这个问题并拥有更灵活的东西,您可以使用
std::common_type_t
,如其他答案中所建议的那样,因此演绎指南变为
template <typename ... Ts>
Tuple(Ts...) -> Tuple<std::common_type_t<Ts...>, sizeof...(Ts)>;
and both cases become Tuple<long, 3u>
并且两种情况都变成
Tuple<long, 3u>
Tuple t1{1l, 2, 3}; // become again Tuple<long, 3u>
Tuple t2{2, 2l, 3}; // now become Tuple<long, 3u>
Perhaps I don't get difference between T...args and typename ...Args and args...
也许我不明白 T...args 和 typename ...Args 和 args 之间的区别...
Look for a good C++ book but, making it simple寻找一本好的 C++ 书籍,但是,让它变得简单
(1) typename ... Args
declare a template variadic sequence of types , for a class/struct, for a using
declaration, for a deduction guide, for a function. (1)
typename ... Args
声明一个模板可变参数类型序列,用于类/结构,用于using
声明,用于推导指南,用于函数。
So所以
template <typename ... Args>
struct foo
{ };
define a template struct that receive zero or more template types arguments and you can declare a variable as follows定义一个接收零个或多个模板类型参数的模板结构,您可以如下声明一个变量
foo<short, int, long, long long> f;
(2) T ... args
declare a variadic template list not of types but of elements of type T
(2)
T ... args
声明一个可变参数模板列表,不是类型,而是类型T
的元素
What is T
?什么是
T
? Another template parameter.另一个模板参数。
So, by example, one of your Tuple
version in your question因此,例如,您的问题中的
Tuple
版本之一
template struct Tuple { /* ... */ };模板结构元组 { /* ... */ };
and a variable should be declared as follows并且变量应该声明如下
Tuple<int, 1, 2, 3> t{1, 2, 3}
that is very redundant in your case.在您的情况下,这是非常多余的。
(3) args...
(with ellipsis after the name) is the use a variadic list (of types or values) (3)
args...
(名称后有省略号)是使用可变参数列表(类型或值)
By example举例
template <typename ... Args>
void foo (Args ... args)
{ bar(args...); }
declare and define a variadic template foo()
function with a template variadic list of types使用模板可变参数类型列表声明和定义可变参数模板
foo()
函数
template <typename ... Args> // <--- declare a variadic list of types Args
and at every type correspond a value, so you declare also a variadic list args
of values并且每种类型都对应一个值,因此您还声明了一个可变参数列表
args
值
void foo (Args ... args) // <--- declare a variadic list of args values of types Args
and the statement expand the pack of values args
and pass they to another function并且该语句扩展值
args
包并将它们传递给另一个函数
bar(args...); // <--- expand the args pack and pass the value to bar.
Alternative using std::index_sequence
:替代使用
std::index_sequence
:
template <typename T, std::size_t> using always_t = T;
template <typename T, typename Seq> struct Tuple;
template <typename T, std::size_t...Is>
struct Tuple<T, std::index_sequence<Is...>>{
T data[sizeof...(Is)];
Tuple(const always_t<T, Is>&... args) : data{args...}{}
};
// Deduction guide (C++17)
template <typename ... Ts>
Tuple(const Ts&...) -> Tuple<std::common_type_t<Ts...>, std::index_sequence_for<Ts...>>;
Tuple a{1,2,3,4,5};
This is surprisingly difficult.这出乎意料地困难。 The only way I could think of making this work is to have the array size as a template parameter, instead of somehow deducing this from the actual constructor parameters, and to use C++17 deduction guides.
我能想到的唯一方法是将数组大小作为模板参数,而不是以某种方式从实际的构造函数参数中推断出来,并使用 C++17 推断指南。
Tested with gcc 9.1, with -std=c++17
:使用 gcc 9.1 测试,使用
-std=c++17
:
#include <cstdlib>
#include <iostream>
#include <type_traits>
#include <utility>
template<typename T, size_t n>
struct Tuple{
T data[n];
template<typename ...Args>
Tuple(Args && ...args):data{std::forward<Args>(args)...}{};
};
template<typename ...Args>
Tuple(Args && ...args)
-> Tuple<std::common_type_t<std::remove_reference_t<Args>...>,
sizeof...(args)>;
Tuple a{1,2,3,4,5};
int main()
{
std::cout << std::is_same_v<decltype(a),
Tuple<int, 5>> << std::endl;
std::cout << a.data[2] << std::endl;
}
based on this good explanation .基于这个很好的解释。
#1 create an array of nth generated integers #1 创建一个由第 n 个生成的整数组成的数组
template <typename Container, int... I>
Container iota_impl(std::integer_sequence<int, I...>) {
return {I...};
}
template <typename T, size_t N>
auto iota_array() {
using Sequence = std::make_integer_sequence<int, N>;
return iota_impl<std::array<T, N>>(Sequence{});
}
...
auto arr1 = iota_array<int, 10>();
will create std::array<int, 10>{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}将创建std::array<int, 10>{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
#2 create an array of integer passed via initializer_list #2 创建一个通过 initializer_list 传递的整数数组
template <typename T, T...I>
auto iota_array2() {
constexpr auto N = sizeof...(I);
return std::array<T, N>({I...});
}
...
auto arr2 = iota_array2<int, 3,2,7,4,5,6>();
will create std::array<int, 6>{3,2,7,4,5,6}将创建std::array<int, 6>{3,2,7,4,5,6}
PS if it should be wrapped in Tuple, it can be. PS如果应该用Tuple包裹,可以。
PPS c++17 PPS c++17
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.