在C++中,有一些情况下,我们需要将tuple或者vector中的值当做参数传递到一个函数当中,传统的做法如下:
std::vector< int> v;
call(v[0], v[1], v[2]);
auto r = std::make_tuple(1, 2.1, 1ull)
call(std::get<0>(r), std::get<1>(r), std::get<2>(r));
我们可以通过如下的方式,将tuple解包传入到函数当中:
#include < iostream>
#include < tuple>
template struct index_sequence { };
template struct make_index_sequence_helper : make_index_sequence_helper { };
template struct make_index_sequence_helper <0, S...> { typedef index_sequence type; };
template using make_index_sequence = typename make_index_sequence_helper::type;
int test(int a, double b) {
std::cout << a << " " << b << std::endl; } template void callFuncHelper(F f, index_sequence, T&& t) { f(std::get(t)...); } template void callFunc(F f, const std::tuple& t) { callFuncHelper(f, make_index_sequence(), t); } int main() { auto inp = std::make_tuple(0, 1.23); callFunc(test, inp); } 前面第一段通过继承机制提供了一个make_index_sequence的模板类,C++14中可以直接使用这个模板类,c++11中需要自己来实现,它是通过继承的方案实现的: 假如N = 4, 那么: make_index_sequence_helper<4>: make_index_sequence_helper<3, 3>;
make_index_sequence_helper<4, 4>: make_index_sequence_helper<2, 2, 3>;
make_index_sequence_helper<2, 2, 3>:make_index_sequence_helper<1, 1, 2, 3>;
make_index_sequence_helper<1, 1, 2, 3>:make_index_sequence_helper<0, 0, 1, 2, 3>;
make_index_sequence_helper<0, 0, 1, 2, 3> {
typedef index_sequence<0, 1, 2, 3> type;
}
test是一个测试函数,callFunc需要两个输入分别是被调用的函数f和一个tuple的参数t,它负责对函数进行调用。它计算出tuple中的元素个数,构造出一个index_sequence传递到callFuncHelper中,由该函数调用std::get对tuple进行解包
我们可以通过如下的方式,将vector解包传入到函数当中
#include < iostream>
#include < vector>
int test(int a, int b) {
std::cout << a << " " << b << std::endl; } template typename std::enable_if::type callFunc(F f, const std::vector& v, Args&&... args) { f(std::forward(args)...); } template typename std::enable_if::type callFunc(F f, const std::vector& v, Args&&... args) { callFunc(test, v, v[N - 1], std::forward(args)...); } int main() { std::vector inp{1, 2}; callFunc<2>(test, inp);
}
test还是我们要测试的函数,前面的callFunc利用了sfinae准则,当N为0的时候,只能对第一个函数进行特化;当N不为0的时候,只能对第二个函数进行特化;通过这种方式,可以将vector进行解包当做参数传到func当中。
当N = n时,解析第n-1个参数,并放在上一轮解析的参数之前,传给下一轮;当N = 0时,对传入的函数进行调用。
需要注意的是,vector的长度必须是在编译期就已知的,或者我们只想取该vector的前某几个参数传到对应的函数中。
当然如果你觉得这个示例中的<2>起来看着不舒服的话,也可以写一个辅助函数,获取test函数的参数数量,然后将这个数量当做模板参数传到callFunc中。
最后,根据上面所述的原理,提供一种tuple转list的方式,并且允许转换的过程中进行一系列的转化操作,编译的时候需要加上-std=c++14:
#include < tuple>
#include < utility>
#include < iostream>
#include < vector>
template
T transfer(T a, T b) {
return a * b;
}
template
std::vector helper(std::index_sequence, const std::tuple& tp) {
return std::vector{transfer(std::get(tp), 3)...};
}
template
std::vector tupleToList(const std::tuple& tp) {
return helper(std::make_index_sequence(), tp);
}
int main() {
auto tp = std::make_tuple(1, 2, 3);
auto r = tupleToList(tp);
for (auto i : r) {
std::cout << i << std::endl; } }