構造体を tuple-like としてアダプトするマクロを書いた
C++11 の規格には,tuple-like という言葉が登場します.これは所謂コンセプトで,tuple-like コンセプトを満たす型 T は,std::tuple_size<T>,std::tuple_element<I, T>,get<I>(t) を持ちます.標準で定義されたものでは,std::pair<T1, T2>,std::tuple<Types...>,std::array<T, N> がこれを満たします.
typedef std::pair<int, double> pair_t; // std::tuple_size static_assert(std::tuple_size<pair_t>::value == 2, ""); // std::tuple_element static_assert(std::is_same<std::tuple_element<0, pair_t>::type, int>::value, ""); // get pair_t p = { 42, 3.14 }; assert((&std::get<0>(p) == &p.first));
さて,ユーザー定義型をこれにアダプトするマクロを書いてみました.
https://github.com/iorate/std-tuple-adapted
使い方は BOOST_FUSION_ADAPT_STRUCT などと似ています.
namespace NS { struct A { int i; double d; }; } IORATE_STD_TUPLE_ADAPT_STRUCT((NS), (A), (i)(d)) void example1() { // std::tuple_size static_assert(std::tuple_size<NS::A>::value == 2, ""); // std::tuple_element static_assert(std::is_same<std::tuple_element<0, NS::A>::type, int>::value, ""); // get NS::A a = { 42, 3.14 }; using std::get; assert((&get<0>(a) == &a.i)); }
注意すべき点として,get<I> は ADL で呼び出すわけですが,その前に get という名前の関数テンプレートを見えるようにしておかなければなりません*1.もっとも,予め using std::get; としておけばよいので,swap と使い方は同じになります.boost::swap に相当するものがあると便利でしょう.上の所に一緒においてあります.
void example2() { std::pair<int, double> p = { 42, 3.14 }; assert((&iorate::get<0>(p) == &p.first); NS::A a = { 42, 3.14 }; assert((&iorate::get<0>(a) == &a.i)); }
また,クラステンプレート用のマクロもあります.
namespace NS { template <class T> struct X { T t; }; } IORATE_STD_TUPLE_ADAPT_TPL_STRUCT((NS), (class T), (X<T>), (t))
最後に,このアダプトが何の役に立つかということですが*2,tuple-like コンセプトを利用したライブラリを使う際に役に立ちます.そのままですね.現在あるライブラリでは,std::tuple_cat などがあります.…それくらいしかありませんが.