[英]Initialize array inside variadic template class
我無法繞開可變的模板。 我想做很簡單的事
Tuple t{1,2,3};
應該包含數組 {1,2,3} ( t.data = {1,2,3}
) 的大小為 3 的元組
這意味着它應該做兩件事:
Tuple<T,3>
大小 3 ( Tuple<>::data[3]
)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};
應該包含
array {1,2,3}
(t.data = {1,2,3}
) 的大小為 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
如果
(std::is_same_v<T, U> && ...)
不為true
,則程序格式錯誤
為了解決這個問題並擁有更靈活的東西,您可以使用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...args 和 typename ...Args 和 args 之間的區別...
尋找一本好的 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, 10>{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, 6>{3,2,7,4,5,6}
PS如果應該用Tuple包裹,可以。
PPS c++17
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.