C++ ときどき ごはん、わりとてぃーぶれいく☆

Wonder Rabbit Projectのなかのひとのブログ。主にC++。

UE4 の UCLASS の定義の基底クラスに名前空間を使っている子が居る場合の不幸と安直な回避策について

現状の UE4C++namespace を使おうと思っても面倒事が増えるだけなので、現実問題としてはわざわざ UE4C++ コードを記述するに当たっては namespace を用いないほうが賢い。少なくとも UE-4.16 現在は。

しかし、そうは言っても、世の中の素敵な C++ ライブラリーを UE4 プロジェクトへ取り込んで使いたい場合もある。単にどこかのメンバー関数から呼び出すだけだとか、そういう場合はたいてい問題は起こらない。しかし、深刻な問題となる場合に遭遇したので tips として紹介したい。

UCLASS で定義する UHogeComponent なり AHogeActor なり、そういったクラスの定義で、素敵な C++er 仕様のきちんと namespace を使ったライブラリーのクラスを継承して使いたい場合があったとしよう。継承じゃなくてコンポジションすればいいとかは本題ではないのでここでの議論は割愛する。

具体例は次の通り:

// MyComponent.h
#pragma once
#include "CoreMinimal.h"
#include <memory>
#include "MyComponent.generated.h"

// UCLASS() 付きで定義するクラスの基底クラスに名前空間付きの
// クラスを使用するコードを書いてしまうとビルド不能に陥る例
UCLASS()
class MyComponent
  : public std::enable_shared_from_this< MyComponent >
{
  GENERATED_BODY()
};

なお、 UE4 では std::enable_shared_from_thisstd::shared_ptr に対応する TSharedFromThisTSharedPtr が用意されているのでこの例の場合はそれらを使うだけでも問題は回避できるが、この例で std::enable_shared_from_this を使ったのは、誰でも C++ 標準ライブラリーのクラスとしてすぐに include してどのような問題が発生するのか試しやすいために選んだ。ついで、 enable_shared_from_thisコンポジションではなく継承で使う理由のある例としても有意性が高い事も選んだ理由に含まれる。

このコードはビルドすると次のようなエラーに見舞われる。

MyComponent.h(11) : Error: Missing '{' in 'Class'

このエラーは C++ コンパイラーの前に UE4UCLASS() などを解釈して独自の追加のヘッダーファイル “MyComponent.generated.h” 等を生成するために動かす UnrealHeaderTool が UCLASS で定義されるクラスについて基底クラス部分やその他あちらこちらでそもそも C++ の namespace 機能が使われる事をまったく想定していないためにパースに失敗して発生してしまう。

悲しい。

しかし、現実問題として我々プログラマーUE4 の世界とは無関係に開発された有用な多くの C++ コード資源を活用して、さくっと目的のプロダクトを開発したい。このような開発に対しては本質的でないトラブルの対応のためにオレオレライブラリーやオレオレラッパーを書いていいのはそれ自体が趣味の場合だけだ。そこで、

// MyComponent.h
#pragma once
#include "CoreMinimal.h"
#include <memory>
#include "MyComponent.generated.h"

// 名前空間を使わないエイリアスを定義
template < typename T > using std_enable_shared_from_this = std::enable_shared_from_this< T >;
// 名前空間を使わないエイリアスを介して UCLASS() 付きのクラスの基底クラスとして使用
UCLASS()
class MyComponent
  : public std_enable_shared_from_this< MyComponent >
{
  GENERATED_BODY()
};

これでいい。少なくとも UnrealHeaderTool が namespace (というか名前空間解決演算子)を考慮していない UE-4.16 執筆現在は。悲しい事だがプログラマーは現実の製品を作ってなんぼ・w・ 未来の UE4 が namespace に美しく対応する日を夢見て現実を乗り越えよう。