それでも構造体を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);
}

[Wandbox]三へ( へ՞ਊ ՞)へ ハッハッ


できないこと

T x={ {},{}/*略*/,{}};

の形式で初期化できない構造体はこの方法は使えない
explicitとかあるとまずいかもしれない
(これに関しては特に困らなさそうなので深く考えていないが、もしかしたらなんかいい方法があるのかもしれない)

また、マクロを使った場合にくらべ型名を取ることができないのでjson objectで鍵を持たせるなどができない


そして最大の問題は手元のコンパイラで動かない。未来はようカモン

最近書いたマクロ(構造体をtupleに変換したい)

これはC++ Advent Calendar 2016の9日目の記事です

はじまり

こんな感じのコードを書いていた

struct try_focus {
    Player p; Card c;
};
string to_json(try_play const &a){
    return make_json("try_play", a.p, a.c);
}
struct try_exc_hand {
    Player p; Card c1;Card c2;
};
string to_json(try_exc_hand const &a){
    return make_json("try_exc_hand", a.p, a.c1, a.c2);
}
struct nodata{};
string to_json(try_exc_hand const &){
    return make_json("nodata");
}
/*以下略*/
struct Key{
    Player p; Card c;
    bool operator<(Key const &rhs){return std::tie(p,c) < std::tie(rhs.p,rhs.c);}
};
struct Key{
    string s;rect r;
    bool operator<(Key const &rhs){return std::tie(s,r) < std::tie(rhs.s,rhs.r);}
};
/*以下略*/
struct pos{
    int p1,p2,p3;
    bool operator==(Key const &rhs)const{return std::tie(p1,p2) == std::tie(rhs.p1,rhs.p2);}
};
/*後で追加したp3を比較要素に追加し忘れた*/

あ!つらい!!
我に二度同じ文言書かすものみな死に絶えればいいのに!!!

はじまり2

そんな分けでいい感じのマクロないかな、とboost内をあさっていたところ BOOST_FUSION_DEFINE_STRUCT_INLINE なる顧客が本当に必要だったものが!
さっそく使おう
(ファンが不吉な音を立て始める)
(IDE候補検索が遅れる、出ない)
(IDEが長考する)
(締め切りがヤバイ)

もうだめだ。自分で書こう

つまりこうなりたいという気持ちがあります

hashとかoperator<とか決まりきった文句はいい感じに定義されててほしいし
to_stringとかto_jsonはちょっと頑張ったら定義できるようにしたい
それらは構造体をtupleに変換できれば解決します

書いた

#define LUCKY_STRUCT_WHITE 

#define LUCKY_STRUCT8_IMPL(name,X1,X2,X3,X4,X5,X6,X7,X8,...) \
struct name##define{ \
    template<class LUCKY_STRUCT_WHITE##X1,class LUCKY_STRUCT_WHITE##X2,class LUCKY_STRUCT_WHITE##X3,class LUCKY_STRUCT_WHITE##X4,class LUCKY_STRUCT_WHITE##X5,class LUCKY_STRUCT_WHITE##X6,class LUCKY_STRUCT_WHITE##X7,class LUCKY_STRUCT_WHITE##X8, class...>struct impl{ \
        LUCKY_STRUCT_WHITE##X1 X1;LUCKY_STRUCT_WHITE##X2 X2;LUCKY_STRUCT_WHITE##X3 X3;LUCKY_STRUCT_WHITE##X4 X4;LUCKY_STRUCT_WHITE##X5 X5;LUCKY_STRUCT_WHITE##X6 X6;LUCKY_STRUCT_WHITE##X7 X7;LUCKY_STRUCT_WHITE##X8 X8; \
        auto operator|(::lucky_struct::to_tie_t){return std::tuple_cat(std::tie(X1),std::tie(X2),std::tie(X3),std::tie(X4),std::tie(X5),std::tie(X6),std::tie(X7),std::tie(X8));} \
        auto operator|(::lucky_struct::get_name_t)const{return #name;} \
    };\
    template<class...T>using type = impl<T... ,void,void,void,void,void,void,void,void>;\
};\
using name=typename name##define::type
#define LUCKY_STRUCT8(name,...) LUCKY_STRUCT8_IMPL(name,__VA_ARGS__, , , , , , , )

8要素までの構造体を定義するマクロのコア部分
tupleに結び付けられるし余計な要素が入ることもない
そしてそこまで重くない(当社比)
[Wandbox]三へ( へ՞ਊ ՞)へ ハッハッ


コードの動き

8要素までだとコードの動きが追いづらいので2要素かつ機能を一部削ったマクロで考える

#define LUCKY_STRUCT2_IMPL(name,X1,X2,...) \
struct name##define{ \
    template<class LUCKY_STRUCT_WHITE##X1,class LUCKY_STRUCT_WHITE##X2, class...>struct impl{ \
        LUCKY_STRUCT_WHITE##X1 X1;LUCKY_STRUCT_WHITE##X2 X2; \
        auto operator|(::lucky_struct::to_tie_t){return std::tuple_cat(std::tie(X1),std::tie(X2));} \
    };\
    template<class...T>using type = impl<T... ,void,void>;\
};\
using name=typename name##define::type
#define LUCKY_STRUCT2(name,...) LUCKY_STRUCT2_IMPL(name,__VA_ARGS__, )
  LUCKY_STRUCT2(Alpha,val)<int>;

このように定義するとマクロはまず以下のように展開される

  LUCKY_STRUCT2_IMPL(Alpha,val,)<int>

引数はname=Alpha,X1=val, X2= となりLUCKY_STRUCT2_IMPLが展開される

struct Alphadefine{
    template<class LUCKY_STRUCT_WHITEval,class LUCKY_STRUCT_WHITE, class...>struct impl{
        LUCKY_STRUCT_WHITEval val;LUCKY_STRUCT_WHITE ;  //1
        auto operator|(::lucky_struct::to_tie_t){return std::tuple_cat(std::tie(val),std::tie());} //2
    };
    template<class...T>using type = impl<T... ,void,void>;
};
using Alpha=typename Alphadefine::type<int>

そしてLUCKY_STRUCT_WHITE が に置換される

struct Alphadefine{
    template<class LUCKY_STRUCT_WHITEval,class , class...>struct impl{
        LUCKY_STRUCT_WHITEval val; ;   //1
        auto operator|(::lucky_struct::to_tie_t){return std::tuple_cat(std::tie(val),std::tie());}  //2
    };
    template<class...T>using type = impl<T... ,void,void>;
};
using Alpha=typename Alphadefine::type<int>

//1の部分
メンバ変数の定義。
X2は空だったので変数名は定義されず、LUCKY_STRUCT_WHITE##X2もLUCKY_STRUCT_WHITEになり空に置換され、第2変数を構成する要素は構造体から消えた
X1は名前を持っていたのでLUCKY_STRUCT_WHITEval val;という定義になる。LUCKY_STRUCT_WHITEval はテンプレート引数として使われる

//2の部分
X1は名前を持っていたのでstd::tie(val)に、X2は空だったのでstd::tie()になった。これらはtuple_catで結合され最終的に1要素のtieが出力される

こうして2要素まで定義できるマクロで1要素の変数を持つ構造体が定義できた
もちろん余計なストレージを所有することなどない
これを8要素に拡張すれば上で定義したものになる。もっと必要なら16や32など拡張してもいいだろう(そんな必要になることはないと思うが)

あとは適当に好きな関数を定義すれば比較も出力も思うが儘だろう
とりあえず比較を実装した
[Wandbox]三へ( へ՞ਊ ՞)へ ハッハッ









つづく

txt-txt.hateblo.jp

じてんしゃそーぎょーさん、しんさくですってよ



おおおおおおおおおおおおおおおおおおおおお(中略。季節が春になるまで叫び続ける)

ちょっとPSVR買ってくる

    • 追記(一時間後ぐらい)

PSVR品薄なのね。初めて知った
あと今日ps4proの発売日なのね
何とか発売までに手に入れないと……。とりあえず明日それっぽい店のぞいてみるか

ボイス付き説が出ているけれどフルボイスとかハーフボイスとかだったりするんだろうか?
文字が見えないけれどどうなるんだろう
ヒロイン子は鮭の一族なんだろか?
しかしこの子いつになく涼しげな恰好をしているな(カコを思い浮かべながら)。何つーか「プレイエリアの外です」が出てきそうな恰好をしているぞ
自転車創業なのに。パンツが禁則されてしまう系世界なのに。
「ひとかけら版」ってなんじゃろ。『※本作はプロローグ版です。』とあるけれどつまり、・・・・・・どういうことだ?
dengekionline.com

とりあえずデジゲー博まで心の一部のどっかしらを温かくして待ってますか

とか言ってたらこんな時間だよ。(161110-0245)

デジゲとか冬コミとかに受かってました

ブログの放置が深刻になってきた。恐ろしい。冬椿です

冬コミとかデジゲー博とかうかってました
デジゲー博;B-16a
冬コミ:西ほ32a


当日はよろしくお願いします

しかしあれから一年か……

夏コミでした。3日目西e-21b「TXT.TXT」で当日はありがとうございました

夏コミでした。twitterで告知はしたのですがこちらではすっかり忘れていました
当日来てくださった方々、ありがとうございました

とりいそぎ、SCE2(ver1.10)がリリースされました

txt-txt.hateblo.jp

先日紹介したSCE2がバージョンアップしました
とうとうあなたにも遊ぶべき絶好のタイミングが訪れたわけです



私はゲームをする業務に戻ります<<起こさないでください>>

ゲーム紹介/「スカイハイ・クロノス・エンドレス」「SCE2」をこれから始めなければならない貴方のための(**いいから俺を信じろ**)

冬椿です。昨日スカイハイ・クロノス・エンドレスをクリアしました
SCE2は今年の初めごろ遊び終えていたようです(調べたら1/27あたりでした)

「スカイハイ・クロノス・エンドレス」「SCE2」とは

川崎部(http://kawasakibu.web.fc2.com/)さんから2012/2014年に公開されたゲームです
スカイハイ・クロノス・エンドレス(以下SCE1)はざっくり言うとあてどもなく空をさまよって素材を集めてさまよう フライングアドベンチャー です
どこまでも続く空とどことない閉塞感があります
ゲームバランスはぶっちゃけ非良心的です

SCE2は(タイトルからもわかる通り)上のSCE1の続編で、こっちは穴を掘ったりする ゲーム となっております

オススメなの?

間違いなくSCE2は死んで生まれ変わっても死ぬまでにやりたいゲームベスト10に確実に入っています
コレ単体でも話としては完結してますが、前作やってからだともっと話が分かるのでSCE1からプレイすることをお勧めしたいです

オススメの遊び方

まずSCE1を遊びます
次にSCE2をプレイします
ナンバリング通り遊ぶのは足し算ができる文明人の嗜みですね


SCE1

ちょうどよい遊び時

やる気が出たら

遊び方

manualと公式サイトを見て、あとはなんか勘で

攻略のヒント

manualと公式サイトを見て
基本死にゲーなので死にましょう
死ぬと最後にセーブしたところか、次の週に入るかを選べます。なのでセーブはそこそこ細目に
人の話はちゃんと聞きましょう。結構有益なことを言っています。それはたいてい後で有益なことを言っていたと気が付く程度です
あとはなんか勘で

EDは全部で5種類あります
実は全5種ではなくて全6種なのですが、6個目のEDは難易度が厳しすぎてwiki見ても全然たどり着けません。割とこのゲームが嫌いになるレベルなので忘れましょう

遊んだあとは

あのゆかいな仲間たちとの別れを惜しみつつ酒飲んで寝ましょう。たぶん疲れてると思うので
んで起きて適当なゲームでもしましょう
1と2はぶっ続けて遊ぶタイプのゲームではないです
気が向いたらED6に挑戦するのもいいかもしれません
ちなみにあらかじめ言っておくと、ゲームバランスに関してSCE2はだいぶ良心的になっています(やったね)

SCE2

ちょうどよい遊び時

思い出したら

遊び方

manualと公式サイトを見て、あとはなんか勘で

攻略のヒント

manualと公式サイトを見て
探索コマンドを有効活用しましょう。私はコレの存在を忘れていて結構うろうろしてました
あとはなんか勘で

面白いの?

例えると?

湿気たパンだと思って口に含んだらパンに殴られた