""
[C++] std::variantを使ってシミュレータでオートプレイさせる
この記事は C++ Advent Calendar 2023 24日目の記事です。
ゲームドメインでのお話です
少し前にC++でAIシミュレータ作ってオートプレイさせてみたので、どんだけの人に刺さる内容かは判らないですが
自分の振り返り的に紹介します
前半が、シミュレータについての話で、
後半が、オートプレイの時に std::variant
が良い感じだった話
です
記載量が多くなってしまいました
前半はC++に直接関係のない話なので、読み物として見て頂ければと思います!
シミュレータとは
シミュレータと聞いてピンとくる方は少ないと思います
実際、自分自身もあまり意味が判っていませんでした
きっかけは、ゲームで機械学習を取り入れるには、シミュレータが必要と聞いたことが始まりです
自分なりにまとめてみると、シミュレータには観点が3つあることに気が付きました
- Ai学習
- テスト
- リプレイ
■ AI学習観点
- 誰かがやったログを再現して、それを学習する
- 自分自身でなんらかのオートプレイを行って、それを学習する
何らかの学習系AIを導入しようと思ったら、必ずシミュレータが必要になります
そして学習するだけでなく、シミュレータでのオートプレイが出来ると以下のように色々と夢も広がります
■ テスト観点
- オートプレイしてくれるってことは、エージングテスト(長時間のオートテスト)出来るね
- プレイしたログを保存し、それを再生したらデグレテストに使えるね(回帰テスト)
こんな感じで
シミュレータがあると、テスト関係の人たちも喜ぶわけです
■ リプレイ観点
- プレイログを保存しておけば、録画再生みたいに後からでも楽しめるね!
- 同期再生にも有効(クライアント間やサーバーとの整合性が取れる)
つまりシミュレータを作ることが出来たら、
- AI学習
- テスト
- リプレイを用いたゲームのプランニングや設計思想
に有効なネタとなりそうです
シミュレータを作るのはちょっと工夫が必要
実際にシミュレータを作るには
周りからの理解も必要であり、性能面でもシビアな要求が求められます
例えば、学習系のAIモデルを作るためのシミュレータであれば、億の回数くらいのバトルはしゃっと実行して欲しいところです
1バトルシミュレーションするのに1分かかります~では話にならないのです
それだと2日経っても3000バトルすらこなせないことになります
そもそも、「●●を入力したら必ず▲▲の結果になること!」という 決定論的シミュレータ を作るのは 最初から設計を考えておく必要があり、後付けでは難しいです
また、キー情報を入力値としてリプレイさせるのは昔からよくある手法だと思いますが
後々のこと(学習系で利用)を考えると、入力値は「キー」ではなく、「状態」が好ましいです
簡単にターン制バトルで言うとこんな感じ
<入力>
「勇者」が「鉄の盾」「鉄の剣」を装備して
「はぐれメタル」に「剣で攻撃」をした
(攻撃力10)
<それを受けた出力>
「はぐれメタル」が(内部防御力9で)
「ダメージ-1」を受けた
(そして逃げるフラグが立った)
※(カッコ)の中は内部パラメータなので、ゲーム画面では見えない情報
こんな感じで「バトルを直接的に変化させる内部状態を入出力の対象にする」のが良いです
「状態」であれば学習系でも利用できるし、何より人が見ても読めます(キー入力よりは…)
→実際に目検で状態を読むのは困難ではありますが…
他にも大量のログを管理する方法なども含めて「シミュレータそのもの」を作るコツはたくさんあるのですが
今回の話題からはちょっと外れるのでこのへんにしときます
作ったシミュレータを活躍させる方法
ヤッター!シミュレータが出来たぞー
同じログを入力したら、同じ結果になったぞー!
と喜んでいるのもつかの間…
苦労して作ったのですが、もちろんそれだけではとある部品が出来ただけなので、何にも良いことはありません
何かの目的があってシミュレータを作ったのでしょうから、それに向かって突き進むべきなのですが
最初に成果が出やすくて、チームに役に立ったと思ってもらえるのは
上に挙げた3つ(Ai学習/テスト/リプレイ)の中でも特に、テスト観点での活用 が良いように思います
テスト観点であれば、本体プロダクトとは別で話を進めやすく、またシミュレータ作成側のエンジニアのみで作業の完結も出来るので、おすすめです
そこでやっと今回の本題に来ました
オートプレイ です!
強化学習にしろ機械学習にしろ、オートプレイは必須!
それがテストにも転用できる!
となれば、時間のかかる学習系を粛々と進めつつ
直近はテスト目的でシミュレータを活躍させるのが良いと思います
→もちろんプランナーが乗り気でリプレイ機能を求めているなら、そっちを作ってください
みんなが学習系に乗り気で、結果をすぐに出したいと思っていても
残念ながらなかなか早期に学習系の結果は出ないのです…
R&D要素の大きく、学習させても期待値に満たない可能性もあります
なのでAI学習目的でシミュレータを作り始めたとしても、テスト活躍案は持っておいた方が良いです
しかもテストでの実績が目に見えて出てくると
リプレイ観点の設計もぐっと提案しやすくなり、録画機能やチート対策などにも話題が広がると思います
→このリプレイ観点の話題は、GDCセッションでもよく出てます
(本当は学習系で成果がポンと出せるのが一番良いのですがね…)
ただし、テスト観点のみで走り進めてしまうと、リプレイ出来ない設計になってしまうこともあります
「テストのためにシミュレータでオートプレイをする」のと
「学習のためにシミュレータでオートプレイをする」のと
「リプレイのためにシミュレータでオートプレイをする」のとだと
結果が似てるようで設計思想が異なるので、良い感じの和集合設計を意識しながら作るのもエンジニアの腕の見せ所ではあります
オートプレイの実装1(とりあえず動作した版)
今回はC++のアドカレ記事で、やっとC++の話が出てきます
長い前置きでしたが、お待たせしました
<前提>
- ターン制バトル
- 敵も味方も、色んな技をいっぱい出し続けたい
- 変な挙動が起きないか?ストップバグなどが無いか?を見る
- 技を出すことが目的なので、自分も相手も無敵モード
- 技を出し尽くしたら、装備を変えて、次のバトルへ遷移する
状況はこんな感じで、実際に実装してみます
<実装例>
main()
で動作するように、1ターンだけオートプレイとして動作するバージョンを例に書いてみました
Conpiler Explorerに全く同じものをアップしています
- 手続き的に実装した版 - Conpiler Explor
https://godbolt.org/z/hxPjz49ab
|
|
出力結果
===AutoPlay===
Attack:10
Summon:2
Buff:5
オートプレイの実装1の考察
これは OrderList
に出せる技をバンバン登録して、それをしていくコードです
■新規に登録する用の型が必要(★0)
OrderList
というリストに登録するための管理用の型 AutoPlayOrder
を新たに作っています
■技にによっては使わないメンバを持っている(★2)
無駄があり、あまり良いコードとは言えないです
そしてこれは、全部の敵や味方が必要な情報を網羅する必要のある神クラスになってしまってます
|
|
ちょっと何とかしたい…
そんな時には、Orderのベースクラスを作って、継承で攻撃クラスを作れば
プレイヤーだけが hitPoint_
のメンバを持てるわけなので
継承するか
数が少ないのであれば、我慢して必要情報を全持ちするかで、とりあえずは動作出来ます
どうしよう…これだけのために継承するのは、依存関係や制約が強すぎる気がします
(今回の場合は継承でリファクタしても悪くないとは思いますが…)
■結局enum判定をがっつりやっている(★1)
技を実行している箇所について↓↓↓
|
|
ここあたりは、std::function
を使ってポリモーフィックで良い感じに見えますが
結局のところ、「何の技を出せる?」という判断をするときに、今時点で何がリストに上がっているか?を調べたくなるので(★3)
(サンプルコードには書いてませんけど)実際はリスト内の OrderType
の enum
をめちゃめちゃ判定に利用しています
つまり実行時のみポリモーフィックにしたところで、結局 enum
で場合分けすることが多いので、あまりうまみが無くてシュン…って感じ
この状態でもオートプレイの動作に問題は無いのですが、リファクタしていこうと思います
オートプレイの実装2(std::variant版)
継承はあんまり使いたくないという発想のもとで、
とりあえず、コンストラクタ生成時の引数制約で、必要な情報を入手するようにします
今回はやってませんが、共通クラスを作ってコンポジションで強制しても良いと思います
また、enum
判定を減らしたいので、std::varriant
を用いて OrderList
に既に登録されている技を型判定無しで取得する手段を提供してみます
- varriantを用いた版 - Conpiler Explor
https://godbolt.org/z/78qx3eTqe
|
|
===AutoPlay===
Attack:20
Summon:2
Buff:5
先ほどは OrderType
のenumを使って、技の処理を振り分けしていたのですが
|
|
これをうまく使うことによって、場合分けしなくて済むようになりました
さっきは、std::function
のおかげで実行時のみは、かろうじてポリモーフィックに動作していましたが、std::variant
のおかげで、他の処理も技の型( OrderType
で持っていたもの)に依存せずに記載することができました(★3’)
また、struct GetCharactorId
や struct ExecuteOrder
を定義する必要があるものの、class OrderAttack
はインタフェースや継承を持っていないので、なんだか自由を手に入れた気分になります
std::variant
を使ってみると、こんな書き方が出来るのか~という自分なりの新たな発見でした
終わりに
今回、シミュレータを作った際に、色々と勉強になることがあったので、ひっくるめて記載してみました
シミュレータという機能がニッチながらも、ゲーム開発においては重要なポイントになりそうなこと、
また今回記載した std::variant
を使って書いた処理は Visitor Pattern というらしいですが
継承、インタフェース、コンポジションなどなど、やりながらあれ?これは?という箇所がたくさんあったので、そういったコードを試行錯誤できたことなどが良い経験だったなーと思って書きました
自分としては継承を使った記載方法でも、今回は良さそうだなと思ったし、
最初に記載した、 AutoPlayOrder
という手続き的な神クラスの記載方法も、技の数が少ないなど状況によってはそこまで悪くないかもなと思いました
シミュレータを突き詰めていくと、技や手札やゲーム環境などのパラメータ追加の容易さと、実行時にいかに高速に動作することが求められてくるので
そうなっていくとまた設計思想も変わってきそうだなとも思いましたが、今回はこのへんまでで終わろうと思います!
参考
std::variant
に気が付けたのは、CppCon2022の Klaus Iglberger さんの
「Breaking Dependencies - The Visitor Design Pattern in Cpp」
というセッションを見て、おおおおおーと思ったからです
- Breaking Dependencies - The Visitor Design Pattern in Cpp
https://www.youtube.com/watch?v=PEcy1vYHb8A
C++を言語にしたデザインパターンの書籍も出されています
- 「C++ソフトウェア設計」(オライリー)
https://www.oreilly.co.jp/books/9784814400454/
この著書の中で、ベースクラスそんなに気軽に更新できないし、純仮想関数を強いた日には同僚とのバーベキューパーティに呼ばれなくなるかもしれないよ!という注釈が何度も出てきて、個人的にウケました
[C++] C++の新しいパターンマッチ「inspect」
この記事は meetup app osaka@7 online への参加記事です
先日 2023/2/20 ごろにISO WG21 C++ 委員会メンバーのAntony PolukhinさんがMedium(Yandexサイト)で 「C++23が完成したよ~」と記事を書かれていました
- C++23 Is Finalized. Here Comes C++26
https://medium.com/yandex/c-23-is-finalized-here-comes-c-26-1677a9cee5b2
それでちょっと新しいC++の機能には何があるのかなと調べていたところ
知らない文法が増えそうな予感の「Pattern Matching」inspect
を見つけたので
それについてメモしてます
これはどこのC++に入るかは決まってないので、将来的には採用されないかもしれないです
<試した環境>
Compiler Explorer
https://godbolt.org/- c++ compiler
x86-64 clang (experimental pattern matching)
- option
-std=c++20
- c++ compiler
サンプルコードはこちら↓↓↓
https://godbolt.org/z/a95M9nxPY
もともとパターンマッチするといえば、こんな感じで switch case
を使ってると思います
|
|
これが、inspect
を用いるとこんな感じに書けます
|
|
文字列マッチもこんな感じに
|
|
タプル的な値のマッチも比較的少ない行数で書ける
|
|
ポリモーフィックに型判定も出来るらしい
というのも、現時点ではまだ実装されていないみたいで動作しなかったです
|
|
これが出来れば、あとはテンプレートのオペレーター演算子も比較的少ない行数で実装できるという…
まだまだ未来の機能ですが、差分学習しておかないと完全に置いて行かれますね…
C++の言語機能は複雑すぎます
とはいえ業務コードでも、競プロなどでも
少ない行数で書けるのはとても良いと思うので(=バグの入る余地が減る)
どんどん進化していってもらいたいですね!
<参考>
Pattern Matching Document #: P1371R2 Date: 2020-01-13 - Open Standards
https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2020/p1371r2.pdfPattern Matching for C++ - Welcome to Bjarne Stroustrup’s homepage!
https://www.stroustrup.com/pattern-matching-November-2014.pdfC++ の歩き方 | cppmap C++23 以降に向けた提案 - C++ の歩き方 | cppmap
https://cppmap.github.io/standardization/cppx/
[C++] VC++でHackerRankの環境構築
この記事は C++ Advent Calendar 2022 7日目の記事です。
(内容まとめ)
競プロ勢にとったら当たり前のローカル環境設定についての記事です
自分の言葉でまとめなおしたメモになります
みんな!AtCoder もいいけど HackerRank も面白いよ!
今年の3月ごろ、同僚(海外の方)から
「HackerRank 結構いいよ、わたしは週末によくやってるよ~」
と教えてもらいまして
たまにポチポチ解いています
- HackerRank
https://www.hackerrank.com/
ざっくり言うと、お題に対するコードを書いて、要求通りの出力が出来れば Pass! でポイントが溜まっていってバッチがもらえたりします
わたしは主にC++の Problem Solving を解いています
(数学系の問題も多いです)
C++ language のジャンルで解くことも出来ますが、こっちは文法問題なので、あまり面白くない
HackerRankは他のオンラインコーディングプラットフォームとはちょっと異なっていて
競技で問題を解いてランクを上げるというよりは、スキルの習得に焦点を当てているような気がします
解いて欲しい問題用の関数がミニマムに提供されてて、最初に記載するであろう入力系の処理が予め記載されているので、解くのに集中出来ますね
で、それまで真面目に Easy
問題を解いていたのですが、簡単すぎるし量も多い…つまらん…
となって、教えてくれた同僚に
「HackerRank、何の問題を解いてる?」
と聞いたところ、
「えぇー Easy
やってるの?時間の無駄だよ~わたしは Hard
しかやらないよ」
と突っ込まれました><。
さてそこで、Hard
問題をやり始めましたが、あら。。。難しい。。。
こんなけ難しかったらデバッグしたくなるんだけど、HackerRankのサイトに組み込まれたコードエディタ上から問題を解くので、プリントデバッグしか方法がない
変数の中身や配列の中身をもっとアグレッシブに確認したい…
前置きが長くなりましたが、HackerRankをやるときに、Visual Studio上でコードを書いて確認する方法を記載しましたmm
<今回の環境>
- Windows10
- Visual Sutdio 2019
- Hacker Rank の C++ 問題を対象
VSにコードコピペしてHackerRankの問題を解きたい
コピペ出来ないとしんどいです!
しかし HackerRank も他の競プロと同じく、#include <bits/stdc++.h> があります
そのまんまじゃリンク通りません
なので、ライブラリを認知する箇所に stdc++.h を置いておけば良いのです
のコピペ元のgist
reza-ryte-club/stdc++.h
https://gist.github.com/reza-ryte-club/97c39f35dab0c45a5d924dd9e50c445f
他にも色んな方が公開されてますけど、検索するとこの方の↑↑↑リンクがよく見つかりました
これを、VC++がデフォで認知する場所に置きます
一番簡単な場所に調べ方は、
|
|
とコードに書いて、F12
で iostream
の場所までジャンプ
→ソースのタブを右クリックすると、そこのディレクトリの場所までジャンプ出来る
ちなみにわたしの場合は、ここにありました
C:\Program Files (x86)
\Microsoft Visual Studio
\2019
\Enterprise
\VC
\Tools
\MSVC
\14.29.30133
\include
エラーやワーニングが出る場合
めんどいですが、毎回エラー除去のための define
を書くのが無難な対応だと思います
(業務のコードじゃないし)
例えば、HackerRank でよく出てくるこんなコード
|
|
エラーになります
error C4996: ‘getenv’: This function or variable may be unsafe. Consider using _dupenv_s instead. To disable deprecation, use _CRT_SECURE_NO_WARNINGS. See online help for details.
あんた getenv
は非推奨だけど使いたいなら、_CRT_SECURE_NO_WARNINGS
定義しなさいよ!ってやつです
ええ、使いたいんです、HackerRank にコードコピペしたいんで!
なのでわたしはガッツリと先ほどの stdc++.h の上の方に定義を追記しています
自分はVSに慣れてるので、慣れた環境でコード書けるのが快適ですね
(余談) VSCodeでやろうとしたが…
最初は、Windoows の VSCode で環境構築をしようとしてたのですが、なかなか手ごわいです…
mac はさくっとものの数分で C++デバッグ環境が構築できたのに
Windows だと、半日かけてもうまく動きませんでした><。
(VC++ がうまく動かなくて、gcc はなんとか動作したって感じです)
色々調べていた時に、VSCode on Windows 情報でいちばん面白かったのが、この中国の投稿サイトでした
- Visual Studio Code はどのように C および C++ プログラムを作成して実行しますか?(翻訳) - zhihu.com
https://www.zhihu.com/question/30315894
わたしは中国語はよくわからないので、Googleのページ翻訳でよくここの Zhihu サイトを見るのですが
この記事は見てて笑っちゃいました。。。
情報量も多いし、皮肉アリ、ぶっちゃけトークありで、読み物として面白かったです
ここを見て、あ、VSCode on Windows でVC++使うのちょっと大変かも…と思いました
中国は同じように感じがあるので、そこの悩みも詳細にかかれてて、親近感沸きました
あんまり日本でこういう記事見ないな~なんでだろ、ぶっちゃけすぎるからかな?
C++だけじゃなくてUnityの情報も多いです、知識投稿サイトってやつかなー?とにかく面白い
(まとめ)
コード書くなら開発環境は整えようね!
C++ で mac なら VSCode だけど、Win なら VS 使おうぜ!
HackerRank ほんとお勧め、地道に解くのが楽しい
(参考)
- Visual StudioでC++のbits/stdc++.hを使う
https://qiita.com/kokosan60/items/d24ab868f7090586b0bc
[C++] 2次元Vectorのメモ
HackerRankやってるときによく2次元配列が出てくるので、ちゃちゃっとやりたいときのメモです
|
|
業務や後に残るコードではなく、とにかくちゃちゃっとやりたい、という要望って
自分はこれまで出会ったことが無かったので
この手のコーディングは、自分的にはかなり新しいというか新鮮な感じがします
[C++] Windowsの空のアプリケーションを作る手順メモ
いつもどうやったっけな?と思って同じ過ちを繰り返してるのでメモ
環境:
Visual Studio 2022
作りたいソリューション
- C++プロジェクト
- ブランクプロジェクト
- Windowsデスクトップアプリケーション(コンソールではない!)
いつもわたし、空のプロジェクトを作りたいからといって
Empty Project
を選んでしまうのです…
すると、コンソールベースの exe を作るソリューションになってしまいます
ちゃうねん、これちゃうねん!
Windowアプリの空のソリューションを作りたい場合はこれ
Create a new project
Windows Desktop Wizard
を選択Configure your new project
で名前を入れて次に進むWindows Desktop Project
でDesktop Application (.exe)
を選択- 更に
Empty project
にチェックを入れる - これで
OK
を押せば、よし!
これこれ、、、これやねん。。。
[C++] ラムダのパラメータリスト()が省略できるようになった
この記事は meetup app osaka@6 の参加記事です。
C++23 でタイトルの通り、パラメータリストのカッコが省略できるようになりました
- Make () more optional for lambdas
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2020/p1102r2.html
gccなら12以上、Clangは14以上で動作するようです
|
|
(もう少し追記するとおもいますが、今はこれで…)
[C++] HackerRank始めました
友達に、HackerRankやってみるといいよと言われたので、始めてみました
- HackerRank
https://www.hackerrank.com/
自分のプロフィールはこれ。。。
まだC++の問題を2問解いただけだけど
https://www.hackerrank.com/haruka_sao
履歴のために、自分の解いたコードをGitHubにアップしたりして…
https://github.com/h-sao/HackerRank/
ランクによってバッチが付きます
ふーん。。HackerRank、こんな感じで解いていくとバッチが付くのか~実績解除していく感じやな pic.twitter.com/AM6d7s6rUU
— 遥佐保 (@hr_sao) January 28, 2022
バッチは Language Proficiency でポイントを稼ぐとスターが付いていく方式です
- 10 ポイントで 1 Star(Bronze)
- …
- 250 ポイントで 5 Star(Gold)
最初に触ってみたのは c++ Language Proficiency Badges だったのですが
どう考えても面白くないというか、C++もう業務で何年も使えてるので
言語のほうは余暇で楽しむとして、アルゴリズム問題のほうを頑張っていこかなと思います
Problem Solving Badges は
- 1 Star - Bronze 30
- 2 Star - Bronze 100
- 3 Star - Silver 200
- 4 Star - Silver 475
- 5 Star - Gold 850
- 6 Star - Gold 2200
こんな感じ…
先は長そうだけど、Gold目指して勉強になりそうだからぼちぼちやってみよかな~
他の競技プロブラムとは違って、自分のペースで取り組めそうなモードなので、わたしには合ってる予感
普段業務で使ってる/使ってたことでも、
自分なりに勉強してバージョンアップしていかないといけないなーと思ってたので、ちょうど良いタイミングで始められたような気がする
(自分が学生だったら、こういうのにめっちゃのめりこんでたんだろうなーと思うと、今の学生さんは環境が良くてうらやましいです)
時代遅れな人にならないように意識していかないとね。。。
[C++] Advent Calendarへの参加履歴 2010-2021
自分メモです
過去に参加した C++ Advent Calendar の自分の記事のリンク
C++ Advent Calendar jp 2010
- [C++]高速化について思うところ
https://h-sao.com/blog/2011/01/01/think-about-sppding-up-cpp/
Boost Advent Calendar 2011
- [Boost/WinRT]Windows8のメトロスタイルアプリでBoost!
http://blog.livedoor.jp/haruka_sao/archives/51954974.html
C++ Advent Calendar jp 2012
- [C++]VisualStudio2012とTaskとAMPの入門
http://blog.livedoor.jp/haruka_sao/archives/52015184.html
C++ Advent Calendar 2013
- [C++]VisualStudio2013NovCTP:C++17(予定)resumable/await紹介
http://blog.livedoor.jp/haruka_sao/archives/52056922.html
C++ Advent Calendar 2021
- [C++] Modulesのコンパイル(MSVC ver)とBMIについて
https://h-sao.com/blog/2021/12/01/about-cpp-modules/
意外と参加してました。。。
こうやって記録に残すのは、なんだか気分が良いですね
[C++] Modulesのコンパイル(MSVC ver)とBMIについて
この記事は C++ Advent Calendar 2021 1日目(初日!)の記事です。
少し前からC++に Modules がやってきました
C++20 対応のメジャーどころのコンパイラ(MSVC/gcc/Clang など)で使うことができます
個人的にはビックウェーブが来たーーーと思ってまして、つねづねポチポチと Modules について調べていました
それを少しまとめたいと思います
モジュールの説明
昔ながらのプリコンパイルヘッダの概念を、今風にした感じでしょうか
ヘッダファイルをインクルードしていたものを Modules に置き換えることが出来ます
ヘッダファイルだと、
インクルードの順番に気を付けたり
コンパイル時間が長くなったり
インクルードガード書いたりと
ゆーてローテク文字列だったのですが、
それがバイナリとして公式に提供されました
Modulesを記載するファイル
各コンパイラによって(推奨)拡張子が異なります
MSVC (cl.exe)
- Foo.ixx
- Foo.ixx
Clang
- Foo.cppm
GCC
- Foo.cc
- Foo.cp
- Foo.cxx
- Foo.cpp
- Foo.c++
- Foo.C
(参考)
- MSVC
Overview of modules in C++ - GCC
GCC and File Extensions - Development with GNU/Linux https://blog.feabhas.com/2021/08/c20-modules-with-gcc11/
以下、、MSVCで話を進めます
(コンパイラによって異なる所が多いので)
モジュールファイルについて
MSVC の場合、モジュールにしたいファイルは .ixx という拡張子を付けます
(Clangだと .cppm、GCCだと .cxx とかになります)
サンプルはこんな感じ
hello.ixx
|
|
利用する側はこんな感じで↓↓↓ import すれば使えます
(従来は #include "hello.h"
とか書いていた場所です!)
|
|
サンプルだけ見ると、なんてことのないコードですね
メイン関数は #include
してた箇所を inport
に変更しただけです
モジュールをバイナリ化する
モジュールを記載する .ixx
ファイルは、.ifc
にプリコンパイルでバイナリ化されます
ややこしいのが、コンパイラによってこのあたりの呼び名が異なってて、こんな感じ
MSVC | Clang | |
---|---|---|
モジュールファイル名 → | .ixx |
.cppm |
モジュールファイルをプリコンパイルしたもの→ | .ifc |
.pcm |
ちなみに「モジュールファイルをプリコンパイルしたもの」を BMI と呼び、
Binary Module Interface の略になります
この BMI ファイルを各 cpp ファイルなどが import
することになります
(参考)
- Practical Cpp Modules - CppCon 2019
https://github.com/CppCon/CppCon2019/blob/master/Presentations/practical_cpp_modules/practical_cpp_modules_boris_kolpackov_cppcon_2019.pdf
VC++でのコンパイル方法
単純のため、まずはコマンドラインでやってみます
利用したVC++バージョンはこちら
コマンドは2つ
|
|
1つ目のコマンドでモジュールをプリコンパイルし、
2つ目のコマンドで obj
をリンク、そして main.exe
の出力をします
<1. モジュールのプリコンパイル>
C:\my\dev\sample_module01>cl /c /std:c++20 hello.ixx
Microsoft (R) C/C++ Optimizing Compiler Version 19.30.30705 for x86
Copyright (C) Microsoft Corporation. All rights reserved.
hello.ixx
これで、hello.obj
と MyHello.ifc
が出来ました
(余談)cl.exe はモジュールのコンパイル時に同時に2つ(
.obj
と.ifc
)のファイルを出力してくれて楽ですClang は別々のコマンドで出力するので、cl.exe とは少し作り方が異なっています
.pcm
( VC++で言うところの.ifc
) を出力した後、それを元に.o
( VC++の.obj
) を出力します
このあたりはまだ次回に投稿したいです
<2. 実行ファイル生成>
C:\my\dev\sample_module01>cl /std:c++20 /EHsc /reference MyHello=MyHello.ifc main.cpp hello.obj
Microsoft (R) C/C++ Optimizing Compiler Version 19.30.30705 for x86
Copyright (C) Microsoft Corporation. All rights reserved.
main.cpp
Microsoft (R) Incremental Linker Version 14.30.30705.0
Copyright (C) Microsoft Corporation. All rights reserved.
/out:main.exe
main.obj
hello.obj
main.exe
が出来ました
実行してみます
C:\my\dev\sample_module01>main.exe
42
問題なし(^^♪
(備考)コンパイルオプションの注意点
VC++のコマンドラインオプションが
- モジュールを作ったとき
- モジュールを使うとき
これらの間で一致していないとき、ワーニングが出ました(C5050
)
main.cpp(7): warning C5050: Possible incompatible environment while importing module ‘MyHello’: _CPPUNWIND is defined in current command line and not in module command line
そのため今回、hello.ixx
内では <iostream>
は利用していないのですが、/EHsc
オプションを付けています
(参考)
- Using C++ Modules in MSVC from the Command Line Part 1: Primary Module Interfaces - C++ Team Blog
https://devblogs.microsoft.com/cppblog/using-cpp-modules-in-msvc-from-the-command-line-part-1/
BMIってなによ?
プリコンパイルされた Binary Module Interface って何なのでしょうか?
この中身は一体?
さんざん調べましたが、大した情報が載ってないですね。。。
これ、BMIというのは Modules を扱うための概念のようです
これはコンパイルの過程のものなので、各コンパイラベンダーが作る箇所であり、明確に公開情報として詳細が提示されているわけではなさそうです
現時点では概念がちらほらと記載されているだけのようでした
実際に、プリコンパイルで作られた .ifc
や .pcm
の中身は
- プリプロセスで利用した情報とか
- ASTのダンプ
- Objみたいなもの
がひとまとめにされてるようです
という記述を見つけましたが、出展元が判らなくなったので、思い出したら追記します。。。
(2021/12/4追記)
CppCon2019の資料が参考になりました!
Practical Cpp Modules - CppCon 2019
https://github.com/CppCon/CppCon2019/blob/master/Presentations/practical_cpp_modules/practical_cpp_modulesboris_kolpackovcppcon_2019.pdf
もちろん、コンパイラによって、さらにバージョンによっても形式は様々なんでしょう
モジュールの配布ってどうやるの?
モジュールのバイナリを配布することはできないです
共有する場合はあくまでソースコードと共に配布になります
また、作られた BMI、つまり .ifc
や .pcm
ファイルは不変的なバイナリではないみたいです
ライブラリのように配布はできないのですね。。。
(余談)Modules の提案を推し進めている Gabriel Dos Reisさん は、Common Module Interface Format を作りたいみたいですが…
具体的に今の段階では、配布目的のものは出ていないようです
(参考)
- C++ Modules: What You Should Know
https://github.com/cppp-france/CPPP-19/blob/master/C%2B%2B_modules_what_you_should_know-Gabriel_Dos_Reis/C%2B%2B_modules_what_you_should_know-Gabriel_Dos_Reis.pdf
所感
まだ2021年12月の時点では、Modules 機能が完全に動作するコンパイラもないみたいですし
そもそも各コンパイラによって記載方法や推奨が異なるので、なんとも道半ばな印象はあります
Modules を利用するための手順やお作法も多く、また情報も限られているので、取り組みにくいですね
マイクロソフトの VC++チームブログ は、コンパイラベンダーとして結構 Moduleds の具体的な情報を出しているように感じました
(Clangももうちょっと頑張って。。。あとGCC。。。おまえはやる気あるのか。。。)
Modules に関して取り組まれている人たちの歴史はとても長く
かつ現在のヘッダファイルがベストだとは思えないので
個人的に一押ししたい機能だと改めて思いました
所感その2
C++ Advent Calendar!
ずいぶん昔に一度だけ参加したことがあったのですが、それからなーんにもしてませんでした
今回、意を決して投稿できて良かったです
かなりよく調べたつもりですけど、間違いなどあったら気軽に @hr_sao まで教えていただけると嬉しいです
C++楽しい~♪
[C++]Compiler Explorerの出力結果の表示方法
Compiler Explorer というオンラインコンパイルサービスがあります
- Compiler Explorer
https://godbolt.org/
書いたC++コードのアセンブリ出力結果をリナルタイムに表示してくれるサービスです
すごーーー👀
初めてこのサービスを見た時には感激しました〜
さておき、
わたし、これで実行結果を見る方法を知らなかったんですね…ハズカシー(*ノдノ)
「Output」を押すと出力結果ウィンドウは出てきますが
このリターン値だけじゃなくて、 std::cout
の結果も欲しいんですけど…👀
ちょっと調べてみたらすぐに判明しました><。
Outputの設定項目に Execute the code のチェックボックスがあるので、それを選択すれば表示されます
出力はこんな感じですね〜
便利です〜