我无法理解可变参数的诱惑。我想做非常简单的事情
Tuple t{1,2,3};
应装箱大小为 3 的包含数组 {1,2,3} 的元组 (t.data = {1,2,3}
(
这意味着它应该做两件事:
- 创建 3 号
Tuple<T,3>
(Tuple<>::data[3]
( - 用数字形式 std::initializer_list 填写
Tuple<>::data
这不起作用:
template<typename T, T...args>
struct Tuple{
T data[sizeof...(args)];
Tuple(const T& args...):data{args...}{};
};
我尝试了各种变化,例如:
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...}{};
};
也许我没有得到两者之间的区别T...args
和typename ...Args
和args...
我试图将此用作简单示例来理解可变参数模板并避免使用std::initializer_list
我无法解决可变参数的诱惑。我想做非常简单的事情
Tuple t{1,2,3};
应装箱大小为 3 的元组,其中包含
array {1,2,3}
(t.data = {1,2,3}
(
不确定,但是,如果我理解正确,您尝试重新创建std::array
.
你想要的在 C++17 之前是不可能的,因为你Tuple
它是一个模板类,所以在 C++17 之前你需要显式模板参数。
从C++17开始,您可以使用扣除指南。
你想要的(再次:如果我理解正确的话(几乎是std::array
演绎指南
template <class T, class... U> array(T, U...) -> array<T, 1 + sizeof...(U)>;
在你的情况下成为
#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>> );
}
请注意,构造函数不是严格必需的,因为参数用于初始化成员(C 样式数组(。
本演绎指南
template <typename T, typename ... U>
Tuple(T, U...) -> Tuple<T, 1 + sizeof...(U)>;
从第一个参数推断Tuple::data
数组的类型,另一个参数仅用于推断数组的大小;如果参数的类型不同,这可能是一个问题;通过示例
Tuple t1{1l, 2, 3}; // become Tuple<long, 3u>
Tuple t2{2, 2l, 3}; // become Tuple<int, 3u>
也算了算,std::array
如果未
true
,则程序格式不正确(std::is_same_v<T, U> && ...)
要解决此问题并具有更灵活的东西,您可以使用std::common_type_t
,正如其他答案中所建议的那样,因此演绎指南成为
template <typename ... Ts>
Tuple(Ts...) -> Tuple<std::common_type_t<Ts...>, sizeof...(Ts)>;
这两种情况都变得Tuple<long, 3u>
Tuple t1{1l, 2, 3}; // become again Tuple<long, 3u>
Tuple t2{2, 2l, 3}; // now become Tuple<long, 3u>
也许我没有得到T之间的区别...参数和类型名称...哗啦啦啦啦�
�
寻找一本好C++书,但要让它变得简单
(1(typename ... Args
为类/结构、using
声明、演绎指南、函数声明一个模板可变参数类型序列。
所以
template <typename ... Args>
struct foo
{ };
定义接收零个或多个模板类型参数的模板结构,您可以按如下方式声明变量
foo<short, int, long, long long> f;
(2(T ... args
声明一个可变参数模板列表,不是类型,而是类型T
元素什么是T
?另一个模板参数。
因此,例如,您的问题中的Tuple
版本之一
模板 结构元组 {/* ... */};
变量应声明如下
Tuple<int, 1, 2, 3> t{1, 2, 3}
在你的情况下,这是非常多余的。
(3(args...
(名称后带有省略号(是使用可变参数列表(类型或值(
通过示例
template <typename ... Args>
void foo (Args ... args)
{ bar(args...); }
声明并定义具有模板可变参数类型列表的可变参数模板foo()
函数
template <typename ... Args> // <--- declare a variadic list of types Args
并且在每个类型对应一个值,因此您还声明了一个值args
的可变参数列表
void foo (Args ... args) // <--- declare a variadic list of args values of types Args
和语句扩展值包args
并将它们传递给另一个函数
bar(args...); // <--- expand the args pack and pass the value to bar.
使用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};
演示
这是非常困难的。我能想到的唯一方法是将数组大小作为模板参数,而不是以某种方式从实际的构造函数参数中推断出来,并使用 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;
}
基于这个很好的解释。
#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>();
将创建std::array<int,>{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
#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>();
将创建std::array<int,>{3,2,7,4,5,6}
PS 如果它应该包装在元组中,它可以是.
PPS c++17