追記
やらないほうがいいようです
https://twitter.com/amedama41/status/817934240360763393
※strict aliasing:コンパイラ的に許可されていない型の間でポインタを通じて行ったり来たり弄ったりすると不思議な力で悲しいことになる。詳しくはググって
------追記ここまで------
目的
構造体をtupleに変換したい
ユーザー定義の構造体に対し、メモリ的に同じレイアウトでtupleに変換可能な構造体を作り、それにユーザー定義構造体をreinterpret_castすることで比較的簡単に自動生成実装できるのではないかと考えてみる
結論から言うとこの方法はそこまで筋がよいわけではなかった
考え方
struct Dog
{
int age;
std::string name;
};
このような構造体に対し
template<class T1,class T2>
struct Foo{
T1 x1;
T2 x2;
};
template<class T>
auto to_tie(T&foo){
return std::tie(foo.x1,foo.x2);
}
このような構造体を用意して
DogをFooにreinterpret_castで変換してやれば値を取り出せるのでないだろうか
その際Dogのメンバ型をFooに知らせるために何らかの方法で明記する必要があるだろう
実装
template<class T1,class T2>
struct Foo{
T1 x1;T2 x2;
};
template<class T1,class T2>
struct foo_adapter{
template<class T>
static auto to_tie(T&x)
{
auto &foo= reinterpret_cast<Foo<T1,T2>&>(x);
return std::tie(foo.x1,foo.x2);
}
};
struct Dog{
using adapt = foo_adapter<int,std::string>;
int age;
std::string name;
};
int main() {
Dog dog={12,"abc"};
auto t=Dog::adapt::to_tie(dog);
t = std::make_tuple(36,"xyz");
std::cout<<dog.age<<dog.name;
}
http://melpon.org/wandbox/permlink/5m5xvpxkkIBBSq85
このような感じになる
構造体を作る側としてはfoo_adapterの引数にメンバの型を列記して定義することで、つまり
using adapt = foo_adapter<int,std::string>;
の一文を追加することで構造体をtupleに変換できるだろう
ちょっとしたassert
foo_adapterの引数を間違えると悲惨なことになる。
以下のようなassert コードを仕込んでおけばコンパイル時に検出できるかもしれない
Dog t={foo.x1,foo.x2}; //型が間違っている場合コンストラクタが正常に働かない
sizeof(Foo) == sizeof(Dog) // 当然同じサイズになるはず
ないよりましだろう
結論
Dogに
auto tie(){return std::tie(age,name);}
を書く方法と比べてやる価値があるかというと疑問が残る
ただ上のちょっとしたassertを仕込んだりfoo_adapter以外のものを使うことで挙動をswitchできたりなどの利点はちょっとありそうだ
ああ、静的リフレクションがほしい