C++11 —— tuple 引數列表解包
阿新 • • 發佈:2018-12-15
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; }