float 変数の UPROPERTY で指定する最大値と最小値を使い回そうとしたところ失敗。
UPROPERTY の UIMin, UIMax, ClampMin, ClampMax に指定する値を変数で指定したらコンパイルエラーになったんだけど、マクロ定数で指定するしかない?
— Saku (@suneo3476Web) 2025年2月7日
UPROPERTY(meta=(ClampMin=123)) // これを
UPROPERTY(meta=(ClampMin=MinVolume)) // こう指定する#UE5
ClampMin はプロパティメタデータ指定子の一つで、プロパティの最小値を指定する*1。 最大値は ClampMax で指定する。 エディターでプロパティのスライダーをドラッグする時の最小値と最大値を指定できる UIMin と UIMax というのもあり、Clamp 系と併用される*2。
ツイートは書き方が間違ってて、ClampMin="123" のように値をダブルクォーテーションで囲う必要がある。
今回気になったのは、値を dynamic に指定できないかどうかだ。 ところが、変数でもマクロでもうまく指定できなかった。
static float MinVolume = -20.0; UPROPERTY(meta=(ClampMin=MinVolume))
これはダブルクォーテーションで囲えてないので失敗したのかと思った。
#define MIN_VOLUME "-20.0" UPROPERTY(meta=(ClampMin=MIN_VOLUME))
マクロでも失敗したのでいよいよ怪しくなってきた。
UPROPERTY がどういうマクロなのかを調べると、純粋な C++ のマクロではないらしいことが分かった。
Unreal’s Reflection system checks every header file before preprocesor swaps directives to the proper code.
(Unreal のリフレクションシステムは、プリプロセッサによりディレクティブを適切なコードに置き換えるよりも先に、すべてのヘッダーファイルを確認します。)
It compiles corectly but Unreal doesn’t see any UFUNCTION/UPROPERTY within a macro. (Using UFUNCTION within a macro)
(プリプロセッサが働いたとしても、Uneral はマクロ内の UFUNCTION/UPROPERTY をマクロとして認識しません(マクロ内に UFUNCTION を書こうが同じこと)。)
Unreal のリフレクションシステム(Unreal Header Tool)は UPROPERTY をパースしてコード生成するやつだ。そして、プリプロセッサは C++ でマクロを置換するやつだ。
UHT がプリプロセッサよりも先に動くということは、UPROPERTY がパースされる前にマクロは置き換えられないということだ。
よって、UPROPERTY にマクロは使えない。
「マクロに UFUNCTION を定義して使用しても意図通りに動かない」という指摘も重要で、Unreal のマクロと C++ のマクロは別のシステムだと考えた方がよい。
とはいえ、ドキュメントには「UCLASSマクロ」という言い回しが使われているので、いつかまた間違えそうだ。 *3。
こういう勘違いで初見の読者が混乱しないように、数値のメタデータ指定子を含んでいる UPROPERTY には、数値が直接書かれている理由をコメントするとよいだろう。
私は忘れっぽいのでプロジェクトのコーディング規約にしてもいいくらいだと思う。
コメント案を AI にいくつか考えてもらった。
2行最大84文字
// UPROPERTY specifier values (ex: UIMin="-20.0") must be written directly // as reflection parsing occurs before macro expansion
2行最大54文字
// UPROPERTY specifier values must be written directly // as reflection parsing occurs before macro expansion
1行72文字
// UPROPERTY values must be direct as reflection processes before macros
1行72文字
// UPROPERTY values need direct writing as reflection runs before macros
2行
// UPROPERTYの指定子(meta=(ClampMin="-20.0")など)はマクロ展開前に // リフレクション処理されるため、直接記述が必要です
1行
// UPROPERTYの指定子はリフレクション処理が先行するため、マクロではなく直接記述が必要 // リフレクション処理がマクロ展開より先のためUPROPERTY指定子は直接記述します // UPROPERTYの指定子はマクロ展開前の処理のため直接記述が必要
なんとかしようがありそうで意外となかった。しょうがないね。