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

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

UE4/C++: DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam と TArray

問題

C++ コードの実装に DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam マクロを使い、パラメーターに TArray を入れて Delay (Blueprintノード右上に時計マークの出るアレ)を経て結果を処理できる非同期動作のデータのジェネレーターを UE4 の勉強と練習として作ってみました。しかし、不思議な事に C++ ソースコードコンパイル(ビルド)は完了し、 UE4Editor も動作するのですが、実際にその実装を Blueprint で試すと、 Blueprint がコンパイルエラーとなり使用できない状況に遭遇しました。

// 例えばこんな動的マルチキャストデリゲートを使おうとする。
// このようにパラメーターに TArray を直接入れると Blueprint で使う段階になってから問題が起こる。
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam( FGenerateMyDataDelegate, TArray< uint8 >, MyData );
// ↑を使ったクラスの例
UCLASS()
class MyExperimental_API UAsyncTaskGenerateMyData
  : public UBlueprintAsyncActionBase
{ GENERATED_UCLASS_BODY()
public:
  UPROPERTY( BlueprintAssignable ) FGenerateMyDataDelegate OnSuccess;
  UPROPERTY( BlueprintAssignable ) FGenerateMyDataDelegate OnFail;
  // 実際にはこのクラスを作って投げる機構なども付ける
  // UE4 標準の AsyncTaskDownloadImage のソースなど参考にするとよい
};

Blueprint で発生するエラーは↓のようになる。

f:id:USAGI-WRP:20180817035243p:plain
f:id:USAGI-WRP:20180817035250p:plain

LogBlueprint: Error: [Compiler VW0_BP] Generate My Data  Signature Error: The function/event 'OnSuccess_C9A93DFE4DF51C0C6C9496873C6AAC62' does not match the necessary signature - has the delegate or function/event changed?
LogBlueprint: Error: [Compiler VW0_BP] Generate My Data  Signature Error: The function/event 'OnFail_C9A93DFE4DF51C0C6C9496873C6AAC62' does not match the necessary signature - has the delegate or function/event changed?

他の型を与えた場合について

ちなみに、パラメーターに TArray ではなく、代替として次のような USTRUCT ラッパーを定義して与えると Blueprint でもコンパイルエラーが発生せずに意図通り動作する。

USTRUCT( BlueprintType )
struct MyDataWrapper
{ GENERATED_BODY()
  TArray< uint8 > MyData;
};
// ラッパーを噛ませたマクロを使うと Blueprint も意図通りに動作可能になる。
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam( FGenerateMyDataDelegate, MyDataWrapper, MyData );

また、 UTexture* など適当なコンポーネント(のポインター)を DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam のパラメーターへ与えた場合も Blueprint は意図通り動作する。

解決

// マクロに対して const & でパラメーターを与えれば TArray を使用し、 Blueprint も意図通りに使用可能になる。
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam( FGenerateMyDataDelegate, const TArray<uint8>&, MyData );

なるほどー😃 C++er にはピンと来る答えです。教えて貰う前に気付けるのが真の C++er とか嫌味を言われそうですが、気にしない。

参考

  1. DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam with TArray - UE4 AnswerHub
    • 今回の記事は UE4 公式の Answers へポストした質問と回答を元に書きました。
    • クールな回答でさくっと教えてくれた Sveitar さん、ありがとうございました😃