tuple 的主要用途,就是把各種類型的參數組合成一個新的數據關聯體(結構體),相當於早期的 std::pair 的泛化版本。
組合存儲是方便了,但是,對於某些特定的應用場景,解包就成了個比較麻煩的事情。為此,我查看 gcc 8.2.0 版的 STL 源碼,從 functional 文件中 提取出 tuple 索引號生成的代碼,並略作更名(避免沖突),得到如下 nstuple 命名空間內的代碼,這其中可變參數模板類的遞歸構建,用得甚是精妙,值得學習。
namespace nstuple
{
template< size_t... _Indexes >
struct X_Index_tuple
{
};
/// Builds an X_Index_tuple< 0, 1, 2, ..., _Num - 1 >.
template< std::size_t _Num, typename _Tuple = X_Index_tuple<> >
struct X_Build_index_tuple;
template< std::size_t _Num, size_t... _Indexes >
struct X_Build_index_tuple<_Num, X_Index_tuple< _Indexes... > >
: X_Build_index_tuple< _Num - 1, X_Index_tuple< _Indexes..., sizeof...(_Indexes) > >
{
};
template< size_t... _Indexes >
struct X_Build_index_tuple< 0, X_Index_tuple< _Indexes... > >
{
typedef X_Index_tuple< _Indexes... > __type;
};
}; // namespace nstuple
有了 nstuple 中的代碼,我們就可以利用 std::get() 操作,輕松的解包 tuple 的各個參數了,實現的示例代碼如下所示:
#include <iostream>
#include <tuple>
#include <utility>
namespace nstuple
{
// 此處省略 nstuple 的代碼,與上面提到的 nstuple 命名空間內的源碼一致
// ......
}; // namespace nstuple
void test_func(int v1, int v2, float v3)
{
std::cout << "(v1, v2, v3) == "
<< "(" << v1
<< ", " << v2
<< ", " << v3
<< ")" << std::endl;
}
using X_Tuple = std::tuple< int, int, float >;
using X_Indices = nstuple::X_Build_index_tuple< std::tuple_size< X_Tuple >::value >::__type;
template< size_t... _Ind >
void _S_Invoke(X_Tuple && xtuple, nstuple::X_Index_tuple< _Ind... >)
{
// 解包 xtuple 參數,傳遞給 test_func() 函數調用
test_func(std::get< _Ind >(std::move(xtuple))...);
}
int main(int argc, char * argv[])
{
X_Tuple xtuple{ 100, 200, 3.141593F };
_S_Invoke(std::forward< X_Tuple >(xtuple), X_Indices());
return 0;
}
