FString as Delegate Payload Data

Hi everyone!

Summary:
I am unable to pass FString as payload data to DelegateXY().BindUObject().

Detailed Description:
I am implementing an OnlineSubsystem and need to pass the Access token (FString) to a HTTP request complete delegate as payload data: *



/* Pseudo: */
FString AccountCredentials.Token;
in32 LocalUserNum;

/* The code in question: */
TSharedRef<IHttpRequest> r = FHttpModule::Get().CreateRequest();
r->OnProcessRequestComplete().BindUObject(this, &FOnlineIdentityXYZ::OnGetUserDataResponse, /* payload data: */ LocalUserNum, AccountCredentials.Token);
// ... 


But then I get



12>D:\...]\Source\Private\OnlineIdentityXYZ.cpp(95): error C2664: 'void TBaseDelegate<TTypeWrapper<void>,FHttpRequestPtr,FHttpResponsePtr,bool>::BindUObject<FOnlineIdentityXYZ,int32,FString>(UserClass *,void (__cdecl FOnlineIdentityXYZ::* )(FHttpRequestPtr,FHttpResponsePtr,bool,int32,FString) const,int32,FString)': cannot convert argument 2 from 'void (__cdecl FOnlineIdentityXYZ::* )(FHttpRequestPtr,FHttpResponsePtr,bool,int32,const FString &)' to 'void (__cdecl FOnlineIdentityXYZ::* )(FHttpRequestPtr,FHttpResponsePtr,bool,int32,FString)'


Since my method accepts const String&, but C++ deduces String as the template paramter, which is acceptible. So I went ahead and explicitly specified the types for the payload data:



r->OnProcessRequestComplete().BindUObject<FOnlineIdentityXYZ, int32, const FString&>(this, &FOnlineIdentityXYZ::OnGetUserDataResponse, LocalUserNum, AccountCredentials.Token);


Which results in the following different compile error:



D:\...]\UnrealEngine\Engine\Source\Runtime\Core\Public\Delegates/DelegateSignatureImpl.inl(512): error C2665: 'TBaseDelegate<TTypeWrapper<void>,FHttpRequestPtr,FHttpResponsePtr,bool>::CreateUObject': none of the 2 overloads could convert all the argument types
  D:\...]\UnrealEngine\Engine\Source\Runtime\Core\Public\Delegates/DelegateSignatureImpl.inl(286): note: could be 'TBaseDelegate<void,FHttpRequestPtr,FHttpResponsePtr,bool> TBaseDelegate<TTypeWrapper<void>,FHttpRequestPtr,FHttpResponsePtr,bool>::CreateUObject<UserClass,int32,FString>(UserClass *,void (__cdecl FOnlineIdentityXYZ::* )(FHttpRequestPtr,FHttpResponsePtr,bool,int32,FString) const,int32,FString)'
          with
          
              UserClass=FOnlineIdentityXYZ
          ]
  D:\...]\UnrealEngine\Engine\Source\Runtime\Core\Public\Delegates/DelegateSignatureImpl.inl(277): note: or       'TBaseDelegate<void,FHttpRequestPtr,FHttpResponsePtr,bool> TBaseDelegate<TTypeWrapper<void>,FHttpRequestPtr,FHttpResponsePtr,bool>::CreateUObject<UserClass,int32,FString>(UserClass *,void (__cdecl FOnlineIdentityXYZ::* )(FHttpRequestPtr,FHttpResponsePtr,bool,int32,FString),int32,FString)'
          with
          
              UserClass=FOnlineIdentityXYZ
          ]
  D:\...]\UnrealEngine\Engine\Source\Runtime\Core\Public\Delegates/DelegateSignatureImpl.inl(512): note: while trying to match the argument list '(FOnlineIdentityXYZ *, void (__cdecl FOnlineIdentityXYZ::* )(FHttpRequestPtr,FHttpResponsePtr,bool,int32,const FString &), int32, const FString)'
  D:\...]\UnrealEngine\Engine\Plugins\Online\OnlineSubsystemXYZ\Source\Private\OnlineIdentityXYZ.cpp(95): note: see reference to function template instantiation 'void TBaseDelegate<TTypeWrapper<void>,FHttpRequestPtr,FHttpResponsePtr,bool>::BindUObject<FOnlineIdentityXYZ,int32,const FString&>(UserClass *,void (__cdecl FOnlineIdentityXYZ::* )(FHttpRequestPtr,FHttpResponsePtr,bool,int32,const FString &),int32,const FString &)' being compiled
          with
          
              UserClass=FOnlineIdentityXYZ
          ]
  D:\...]\UnrealEngine\Engine\Plugins\Online\OnlineSubsystemXYZ\Source\Private\OnlineIdentityXYZ.cpp(95): note: see reference to function template instantiation 'void TBaseDelegate<TTypeWrapper<void>,FHttpRequestPtr,FHttpResponsePtr,bool>::BindUObject<FOnlineIdentityXYZ,int32,const FString&>(UserClass *,void (__cdecl FOnlineIdentityXYZ::* )(FHttpRequestPtr,FHttpResponsePtr,bool,int32,const FString &),int32,const FString &)' being compiled
          with
          
              UserClass=FOnlineIdentityXYZ
          ]


Passing a reference doesn’t seem to be enough anyway, since the data will get deallocated before the delegate is called, so I am guessing my approach must be entirely wrong. (I hoped the BindUObject would magically do all the necessary copying etc.)

I also tried FString directly (by-“value”), which would probably result in 2 copies instead of the one required (the performance doesn’t really matter here, but ugh). Then the compiler complains about raw pointers not being allowed in delegates.

  • The access token needs to be passed to the FUserOnlineAccountXYZ constructor which is called in the bound delegate. I understand that a alternative is to create the FUserOnlineAccountXYZ, pass a SharedPtr/SharedRef to the delegate and use setters. I want the object to be immutable, though. Apart from that I am sure that this use case will appear for me in the future again, one way or another.

Answers that would help:
If you can answer one of these questions, I would be able to find a clean solution:

  • How do I create a SharedRef from an FString? (MakeShareable(myStr))? And would that be the intended/recommended way of doing this?
  • Do you know code in the engine, where this is done?
  • Do you know a open source plugin, where this has been done?
  • Do you know some line of documentation that states this is not possible by design?

I can imagine a ton of ugly workarounds (like passing a pointer to a heap allocated char array as long for example, creating a member array of strings and passing the index etc.). What I’m looking for is either a clean solution or documentation that explicitly states this is impossible.

Thank you very much in advance!

The solution was that FOnlineIdentityXYZ is not a UObject and I can therefore not use BindUObject, but must use BindRaw instead. In addition I am now using



TSharedPtr<FString> shareableToken = MakeShareable<FString>(new FString(AccountCredentials.Token));


… and pass that to BindRaw to ensure the FString isn’t dealocated when it goes out of scope.
May this help someone else out there!