それでも構造体をtupleに変換したい
前 最近書いたマクロ(構造体をtupleに変換したい) - TXT.TXT
これもC++ Advent Calendar 2016の9日目の記事です
はじまり
struct S { int x; std::string s; };
構造体に
bool operator<(S const&lhs,S const&rhs) { return std::tie(lhs.x,lhs.s) < std::tie(rhs.x,rhs.s); }
自動生成できるものを自動生成したい
それにはやっぱりtupleへの変換が必要だ
構造化束縛なら?
C++17(1z)で構造化束縛(Structured Bindings)という機能が入る
C++1z 構造化束縛 - Faith and Brave - C++で遊ぼう
詳しくは上などを見てほしいが結論を言うと
template<class T> auto to_tie(T&&s) { auto &[x1,x2] =s; return std::tie(x1,x2); }
こういうこういう関数が作れる
[Wandbox]三へ( へ՞ਊ ՞)へ ハッハッ
ただ残念ながら自分は[X1,X2]の部分を可変長にする方法は知らない
これは必要なだけ書きなぐれば解決するのでそこまで困らないのだが
問題はこれをSFINAEの文脈で使う方法を思いつかないので適切な関数に振り分ける方法が思いつかない
なのでコンストラクタの引数の数から推定しようと思う
万能解とは言えないが、今回のケースではうまく行くし大丈夫な時は大丈夫だろう
だめでも構造化束縛で失敗するだろうし
実装
面倒なので1-3要素まで
まず構造体の引数の数をコンストラクタの引数の数から推測する
template<class T>auto impl(Nice<3>*)->decltype(T{{},{},{}},Idx<3>{}){return {};} template<class T>auto impl(Nice<2>*)->decltype(T{{},{}},Idx<2>{}){return {};} template<class T>auto impl(Nice<1>*)->decltype(T{{}},Idx<1>{}){return {};} template<class T> auto len(){return impl<T>(static_cast<Nice<3>*>(nullptr));}
それを元に構造体束縛でtieする
template<class T> auto impl2(T&s,Idx<1>){auto &[x1] = s;return std::tie(x1);} template<class T> auto impl2(T&s,Idx<2>){auto &[x1,x2] = s;return std::tie(x1,x2);} template<class T> auto impl2(T&s,Idx<3>){auto &[x1,x2,x3] = s;return std::tie(x1,x2,x3);} template<class T> auto to_tie(T&s){return impl2(s,len<T>());}
後はそれを元にやりたいことをやる
template<class T> bool cmp(T const&lhs,T const&rhs) { return to_tie(lhs) < to_tie(rhs); }