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!