首先,指數陣列的簡要概述:
template<std::size_t ...S>
struct seq { };
// And now an example of how index arrays are used to print a tuple:
template <typename ...T, std::size_t ...S>
void print_helper(std::tuple<T...> tup, seq<S...> s) {
// this trick is exceptionally useful:
// ((std::cout << std::get<S>(tup) << " "), 0) executes the cout
// and returns 0.
// { 0... } expands (because the expression has an S in it),
// returning an array of length sizeof...(S) full of zeros.
// The array isn't used, but it's a great hack to do one operation
// for each std::size_t in S.
int garbage[] = { ((std::cout << std::get<S>(tup) << " "), 0)... };
std::cout << std::endl;
}
現在使用我們的print_helper功能:
int main() {
print_helper(std::make_tuple(10, 0.66, 'h'), seq<0,1,2>());
return 0;
}
雖然,打字seq<0,1,2>
可能有點痛苦。因此,我們可以使用模板遞歸來創建一個類來生成seq
S,使gens<3>::type
相同seq<0,1,2>
:
template<std::size_t N, std::size_t ...S>
struct gens : gens<N-1, N-1, S...> { };
template<std::size_t ...S>
struct gens<0, S...> {
typedef seq<S...> type;
};
int main() {
print_helper(std::make_tuple(10, 0.66, 'h'), gens<3>::type());
return 0;
}
由於N
在gens<N>::type
將永遠是在元組元素的數量,你可以用print_helper
,使其更容易:
template <typename ...T>
void print(std::tuple<T...> tup) {
print_helper(tup, typename gens<sizeof...(T)>::type());
}
int main() {
print(std::make_tuple(10, 0.66, 'h'));
return 0;
}
注意,模板參數可以自動推導(輸入了這一切,將是一個痛苦的人會不是嗎?)。
現在,tuple_zip
功能:
和以前一樣,開始與助手功能:
template <template <typename ...> class Tup1,
template <typename ...> class Tup2,
typename ...A, typename ...B,
std::size_t ...S>
auto tuple_zip_helper(Tup1<A...> t1, Tup2<B...> t2, seq<S...> s) ->
decltype(std::make_tuple(std::make_pair(std::get<S>(t1),std::get<S>(t2))...)) {
return std::make_tuple(std::make_pair(std::get<S>(t1), std::get<S>(t2))...);
}
的代碼是有點棘手,尤其是尾部的返回類型(返回類型聲明作爲auto
並且在參數被定義之後與->
一起提供)。這讓我們避免甚至定義返回類型是什麼,問題簡單地宣佈它會返回在函數體中使用表達式(如果x
和y
是int
S,delctype(x+y)
是在編譯時解析爲int
)。
現在把它包在提供使用適當的seq<0, 1...N>
gens<N>::type
功能:
template <template <typename ...> class Tup1,
template <typename ...> class Tup2,
typename ...A, typename ...B>
auto tuple_zip(Tup1<A...> t1, Tup2<B...> t2) ->
decltype(tuple_zip_helper(t1, t2, typename gens<sizeof...(A)>::type())) {
static_assert(sizeof...(A) == sizeof...(B), "The tuple sizes must be the same");
return tuple_zip_helper(t1, t2, typename gens<sizeof...(A)>::type());
}
現在你可以使用它作爲問題規定:
int main() {
auto tup1 = std::make_tuple(1, 'b', -10);
auto tup2 = std::make_tuple(2.5, 2, std::string("even strings?!"));
std::tuple<
std::pair<int, double>,
std::pair<char, int>,
std::pair<int, std::string> > x = tuple_zip(tup1, tup2);
// this is also equivalent:
// auto x = tuple_zip(tup1, tup2);
return 0;
}
最後,如果你提供一個<<
operator std::pair
您可以使用我們上面定義的打印功能打印壓縮結果:
template <typename A, typename B>
std::ostream & operator << (std::ostream & os, const std::pair<A, B> & pair) {
os << "pair("<< pair.first << "," << pair.second << ")";
return os;
}
int main() {
auto tup1 = std::make_tuple(1, 'b', -10);
auto tup2 = std::make_tuple(2.5, 2, std::string("even strings?!"));
auto x = tuple_zip(tup1, tup2);
std::cout << "zipping: ";
print(tup1);
std::cout << "with : ";
print(tup2);
std::cout << "yields : ";
print(x);
return 0;
}
的輸出是:
壓縮和解:1個B 10
用:2.5 2甚至串?
收率:對(1,2.5)對(B,2)對(10,即使字符串?)
像std::array
,std::tuple
是在編譯時定義,並且因此它可以被用來生成更優化的代碼(與容器相比,在編譯時已知更多信息,如std::vector
和std::list
)。所以,即使有時候有些工作,你也可以使用它來製作快速且聰明的代碼。快樂黑客!
編輯:
按照要求,允許不同的尺寸,並與空指針填充的元組:
template <typename T, std::size_t N, std::size_t ...S>
auto array_to_tuple_helper(const std::array<T, N> & arr, seq<S...> s) -> decltype(std::make_tuple(arr[S]...)) {
return std::make_tuple(arr[S]...);
}
template <typename T, std::size_t N>
auto array_to_tuple(const std::array<T, N> & arr) -> decltype(array_to_tuple_helper(arr, typename gens<N>::type())) {
return array_to_tuple_helper(arr, typename gens<N>::type());
}
template <std::size_t N, template <typename ...> class Tup, typename ...A>
auto pad(Tup<A...> tup) -> decltype(tuple_cat(tup, array_to_tuple(std::array<std::nullptr_t, N>()))) {
return tuple_cat(tup, array_to_tuple(std::array<std::nullptr_t, N>()));
}
#define EXTENSION_TO_FIRST(first,second) ((first)>(second) ? (first)-(second) : 0)
template <template <typename ...> class Tup1, template <typename ...> class Tup2, typename ...A, typename ...B>
auto pad_first(Tup1<A...> t1, Tup2<B...> t2) -> decltype(pad<EXTENSION_TO_FIRST(sizeof...(B), sizeof...(A)), Tup1, A...>(t1)) {
return pad<EXTENSION_TO_FIRST(sizeof...(B), sizeof...(A)), Tup1, A...>(t1);
}
template <template <typename ...> class Tup1, template <typename ...> class Tup2, typename ...A, typename ...B>
auto diff_size_tuple_zip(Tup1<A...> t1, Tup2<B...> t2) ->
decltype(tuple_zip(pad_first(t1, t2), pad_first(t2, t1))) {
return tuple_zip(pad_first(t1, t2), pad_first(t2, t1));
}
而且順便說一句,你將需要這個,現在使用我們的方便的print
功能:
std::ostream & operator << (std::ostream & os, std::nullptr_t) {
os << "null_ptr";
return os;
}
現在的獎金:1 /你可以使它工作,即使是不等長的元組(例如填充'nullptr_t')?和更多的參與2 /你可以使它與任意數量的元組一起工作嗎? –
* zip兩個元組* *是什麼意思?你能發佈預期的結果嗎? –
@BЈовић我在下面的答案中添加了最終'main'例程的所需輸出。通過zip,我的意思是拿上面的兩個元組('tup1'和'tup2'),並在這種情況下創建一個包含3個元素的元組,其中第一個元素是'make_pair(1,2.5)'等等 – user