如何遍歷 std::tuple?
希望以 C++11 實現,不要 C++14 或更新的標準
正好最近寫過一些模板,試著來答一下。
---------------- 無視部分開始的分割線 ----------------(下面這段寫的像*一樣還是別看了……寫模板寫傻了的產物)首先,實現一個 C++14 才有的 std::make_index_sequence (C++11可用,參考Implementation C++14 make_integer_sequence):template &
struct Base {};
template &
struct Concat_;
template &
using Concat = typename Concat_&
template &
struct Concat_&
using Type = Base&
};
template &
struct Index_;
template &
using Index = typename Index_&::Type;
template &
struct Index_&::type&> {
using Type = Base&;
};
template &
struct Index_&::type&> {
using Type = Concat&
};
然後來實現一下遍歷器(參考Prameter pack):
template &
struct A_ {};
template &
using A = A_&
template &
struct A_&
template &
static void a(const Tup tup, F f) {
int dummy[] = { (f(std::get&
(void)dummy;
}
};
最後來遍歷一下:
struct C {
template &
void operator ()(T t) { std::cout &<&< t &<&< std::endl; }
};
int main() {
auto tup = std::make_tuple(42, 0.5, "F**k the template");
A&
return 0;
}
輸出:
42
0.5
F**k the template
---------------- 無視部分結束的分割線 ----------------
似乎寫複雜了,也許正確的做法是直接遞歸模板:template &
struct B;
template &
struct B&
template &
static void b(const Tup tup, F f) {}
};
template &
struct B&
template &
static void b(const Tup tup, F f) { f(std::get&(tup)); B&
};
template &
struct B&
template &
static void b(const Tup tup, F f) { f(std::get&(tup)); }
};
然後
struct C {
template &
void operator ()(T t) { std::cout &<&< t &<&< std::endl; }
};
int main() {
auto tup = std::make_tuple(42, 0.5, "F**k the template");
B&
return 0;
}
結果一樣(逃
(目測會掉粉自己來答一下吧。
最後我順著 @Irons Du 和 @悲鳴 給的模板偏特化思路,寫了個通用版本:// tuple_iterator.h
#include &
template&
struct TupleIterator final {
TupleIterator() = delete;
template&
inline static void iterate(
const TupleType t,
void f(const typename std::tuple_element&
ArgTypes... args)
{
TupleIterator&
f(std::get&
}
};
template&
struct TupleIterator&
TupleIterator() = delete;
template&
static void iterate(
const TupleType ,
void (const typename std::tuple_element&<0, TupleType&>::type , ArgTypes...),
ArgTypes...)
{
}
};
// 這個是為了支持空的 tuple&<&>() 的情況
template&
void TupleForEach(const std::tuple&<&> , void (ArgTypes...), ArgTypes...)
{
}
template&
void TupleForEach(const TupleType t,
void f(const typename std::tuple_element&
TupleType&>::type ,
ArgTypes...),
ArgTypes... args)
{
TupleIterator&
}
用的時候大概是這樣:
#include &
#include &
#include "tuple_iterator.h"
using std::ostream;
using std::cout;
using std::endl;
using std::make_tuple;
// 執行的函數必須是這樣的形式,第一個參數是 tuple 元素的類型,返回值是 void
template&
void PrintTupleElement(const T element, ostream *os)
{
*os &<&< element &<&< ", ";
}
// 如果要處理空 tuple&<&>(),則寫一個不含有第一個參數,其他參數類型相同的重載函數,內容可以是空
// 不知道對於 tuple&<&>() 有什麼更好的解決方法
void PrintTupleElement(ostream *os)
{
}
int main()
{
auto t = make_tuple(1, 2.3, "a");
cout &<&< "(";
TupleForEach(t, PrintTupleElement, cout);
cout &<&< ")" &<&< endl;
return 0;
}
template&
struct TupleReader
{
static void read(const rapidjson::Value msg, Tuple t)
{
TupleReader&
if (msg.IsObject())
{
rapidjson::Value::ConstMemberIterator itr = msg.FindMember(std::to_string(N - 1).c_str());
readJson((*itr).value, std::get&
}
}
};
template& https://github.com/IronsDu/dodo/blob/master/src/rpc/JsonRpc.h#L133
struct TupleReader &< Tuple, 1 &>
{
static void read(const rapidjson::Value msg, Tuple t)
{
if (msg.IsObject())
{
rapidjson::Value::ConstMemberIterator itr = msg.FindMember("0");
readJson((*itr).value, std::get&<0&>(t));
}
}
};
去看get的源碼----遍歷的話好像去看tie更直接一點...
用lambda遍歷吧:
template&
void tuple_for_each(const std::tuple&
{
__tuple_processor&
}
template&
struct __tuple_processor
{
inline static void __tuple_process(const Tuple t, Func f)
{
__tuple_processor&
f(std::get&
}
};
template& 測試:
struct __tuple_processor&
{
inline static void __tuple_process(const Tuple t, Func f)
{
f(std::get&<0&>(t));
}
};
int main()
{
auto t1 = std::make_tuple(1, "2", 3.4f);
int n = 5;
auto t2 = std::tuple_cat(t1, std::tie(n), std::make_pair(6, 7));
tuple_for_each(t2, [](auto val) { std::cout &<&< val &<&< " "; });
}
輸出:
1 2 3.4 5 6 7
//遍歷輸出tuple元素的簡潔方式(C++11)
//Win32Con17_VS2017_01.cpp
#include &
#include &
using namespace std;
template&
void myprint_impl(tuple&
{
cout &<&< tup._Myfirst._Val &<&< ((tup._Mysize &> 1) ? ", " : ""); //輸出tup的頭1項
myprint_impl(tup._Get_rest()); //對除頭1項之外的tup遞歸調用
}
template&<&>
void myprint_impl(tuple&<&> tup) //終止條件
{
cout &<&< endl;
}
int main()
{
auto t = make_tuple(3, 4.67, "Hello", true);
myprint_impl(t); //3, 4.67, Hello, 1
system("pause");
return 0;
}
#include &
#include &
using namespace std;
template&
struct print_tuple {
void operator() (tuple&
cout &<&< get&
}
};
template&
struct print_tuple&<0, Ts...&> {
void operator() (tuple&
cout &<&< get&<0&>(t) &<&< endl;
}
};
template&
void print(tuple&
const auto size = tuple_size&
print_tuple&
}
int main(void) {
auto t = make_tuple(1, 2, "abc", "def", 4.0f);
print(t);
return 0;
}
// from Iterating over a std::tuple
你是想要用std::apply展開std::tuple嗎?
推薦閱讀:
※目前是否有C++提案是關於在編譯期獲取類/結構體成員變數的?
※如今C++在非底層環境下還有多少地位?
※為什麼非指針對象不能使用const成員函數?
※迭代器尾後元素的設計是出於什麼意圖?