简体   繁体   English

在可变参数模板类中初始化数组

[英]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:这意味着它应该做两件事:

  • Create Tuple<T,3> size 3 ( Tuple<>::data[3] )创建Tuple<T,3>大小 3 ( Tuple<>::data[3] )
  • fill Tuple<>::data with the numbers form std::initializer_list用 std::initializer_list 形式的数字填充Tuple<>::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...argstypename ...Argsargs...

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 not true如果(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};

Demo演示

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM