Array of Interfaces, blueprintable c++ function parameter

Having some issues getting an array of interfaces as a function parameter for a function tagged as “BlueprintCallable”

The following works if the function is NOT tagged as blueprint callable, ie:

void MyFunction(TArray<TScriptInterface<IInterface>> foo);

But if you try to make it integrate with blueprint, as an example like so:

UFUNCTION(BlueprintCallable, Category = Debug)
void MyFunction(TArray<TScriptInterface<IInterface>> foo);

It will refuse to compile.

I’m just wondering what the generally accepted syntax is to do this?

Hey Hennez-

It should be possible to create a function that accepts an array as a parameter. What is the exact error you get when trying to compile with the UFUNCTION() in place?

Hey , thanks for responding -

The error is:
TScriptInterface’ : unspecialized class template can’t be used as a template argument for template parameter ‘InElementType’, expected a real type

Also edited the question, realised it had butchered the examples since I didn’t have them as code segments, you should be able to make more sense of the examples now.

Hey Hennez-

Have you taken a look at the documentation for exposing interfaces to blueprints? If you are having problems getting this to compile you may want to check out this link for how to setup an interface in code and access it through blueprints: A new, community-hosted Unreal Engine Wiki - Announcements - Epic Developer Community Forums

Cheers

Hey ,
Thanks for the link, though the issue here isn’t to do with the interface set-up. The interface is set-up and exposed to blueprint all fine, I can call it’s functions etc. This is more specific to passing a reference to that interface, and more specifically again an array of them.

The following code for instance works fine to pass a single reference of an interface:

UFUNCTION(BlueprintCallable, Category = Debug)
 void MyFunction(TScriptInterface<IInterface> foo);

But it’s not recognizing it as a ‘real’ parameter type when I add on the TArray at the front.

Hey Hennez-

After further investigation it seems that there is a bug with passing an array of interfaces into a function. This bug has been recorded for further investigation (UE-21971).

Cheers

I’m having this same issue. +1 for a solution!

Hey alk3ovation-

I have entered a bug for this issue (UE-21971) and noted the increased interest in a fix. Unfortunately there isn’t a workaround for passing an array of interfaces at this time.

Any update on this ? Seems to still be an issue in 4.10.1

Hey -

This issue is still open in our database. I have added a comment to the bug report to indicate that this is still affecting people and will update here when there is a change in the status.

Cheers

Thanks for your help!

Oh, I just discovered another problem with TScriptInterface. If you try to define a blueprint native like this:

UFUNCTION(BlueprintNativeEvent, BlueprintCallable, Category = Skill Management")
void GetSkill(TScriptInterface foo);

virtual void GetSkill_Implementation(TScriptInterface foo);

and then in your cpp you define _Implementation (as usual):

void MyClass::GetSkill_Implementation(TScriptInterface foo) { … }

And then try to compile it will complain about
“GetSkill(const TScriptInterface &)': overloaded member function not found”

Hey ,

Pretty sure this is just a case of the UHT changing the parameters slightly, it does it with TScriptInterface<> and TArray<> that I’ve noticed.

When you define the function, try giving it what it wants, so instead of:

 void GetSkill(TScriptInterface foo)

try using:

 void GetSkill(const TScriptInterface<>& foo)

and it should compile and work for you

You’re right - I didn’t initially notice that it complained about not finding reference type. Changing my functions to use reference instead of value fixes it. Thanks

The dev-team is probably already aware of this, the problem is that the generated code in .generated.h is incorrect.
A function like this:

.h

UFUNCTION(BlueprintCallable, Category = "My Category")
void MyFunction(TArray<TScriptInterface<IMyInterface>> const & Parameter);

becomes (note the first argument for the P_GET_TARRAY_REF macro (which is supposed to be the type):

.generated.h

#define <path to file>_h_<line number of GENERATED_BODY() macro>_RPC_WRAPPERS[_NO_PURE_DECLS] \
 \
 ...\
	DECLARE_FUNCTION(execMyFunction) \
	{ \
		P_GET_TARRAY_REF(TScriptInterface,Z_Param_Out_Parameter); \
		P_FINISH; \
		this->MyFunction(Z_Param_Out_Parameter); \
	} \
 ...

One workaround could be to wrap the parameter in a USTRUCT or simply provide a CustomThunk yourself. Simply mark your UFUNCTION with the CustomThunk specifier (https://docs.unrealengine.com/latest/INT/Programming/UnrealArchitecture/Reference/Functions/Specifiers/CustomThunk/index.html) and add this code to your .h (for my example above):

DECLARE_FUNCTION(execMyFunction)
{
	P_GET_TARRAY_REF(TScriptInterface<IMyInterface>,Z_Param_Out_Parameter);
	P_FINISH;
	this->MyFunction(Z_Param_Out_Parameter);
}

That works for me, hope it helps someone else encountering this.

So I’ve just encountered this problem again yesterday. This time I decided to take a closer look and see what I could do to fix it once and for all. As it turns out only very few lines are needed to handle this specific case.
I’ve submitted a Pull Request #2468 with the necessary changes.
If you don’t want to wait, here is the commit

Edit: forgot to mention, my change is based on the 4.11.0 release branch

Thanks. Hope they will integrate it soon.

Just to let it known, i temporarly resolved it copy/pasting the generated code and modifying it (using CustomThunk).

Example:

UFUNCTION(BlueprintNativeEvent, BlueprintCallable, CustomThunk, Category = "MyHUD")
	void MyOnSelectionChange(class UMainInGameWidget* MainHUD, const TArray<TScriptInterface<IEntityInterface>> & CurrentSelection );
	virtual void MyOnSelectionChange_Implementation(class UMainInGameWidget* MainHUD, const TArray<TScriptInterface<IEntityInterface>> & CurrentSelection);
	DECLARE_FUNCTION(execMyOnSelectionChange)
	{
		P_GET_OBJECT(UMainInGameWidget, Z_Param_MainHUD); 
		P_GET_TARRAY_REF(TScriptInterface<IEntityInterface>, Z_Param_Out_CurrentSelection); 
		P_FINISH; 
		this->MyOnSelectionChange_Implementation(Z_Param_MainHUD, Z_Param_Out_CurrentSelection);
	}