Cast TScriptInterface to other Interface

Hi there,

I have a question regarding the proper use of TScriptInterface. Say, I have two interfaces, IMyInterface1 and IMyInterface2, and an actor AMyActor which implements both interfaces. If I now have a variable of type TScriptInterface(IMyInterface1) (can’t use angular brackets in normal text…), how would I go about obtaining a variable of type TScriptInterface(IMyInterface2) of the same underlying object, without having to do an intermediate cast to AMyActor? I know it is possible doing the following:

TScriptInterface<IMyInterface1> x;
AMyActor* myActor = Cast<AMyActor>(x.GetObject());
TScriptInterface<IMyInterface2> y = TScriptInterface<IMyInterface2>(myActor);

If I were using raw pointers, I would simply do

IMyInterface1* x;
IMyInterface2* y = Cast<IMyInterface2>(x);

What I’d love to be able to do, would be:

TScriptInterface<IMyInterface1> x;
TScriptInterface<IMyInterface2> y = TScriptInterface<IMyInterface2>(x.GetObject());

The reason I can’t use raw pointers, is that passing raw pointers to an RPC is not possible, and raw interface pointers also cannot be used as UPROPERTYs. I don’t want to cast to AMyActor, because I also have other actor-types that implement both interfaces, so I would have to try to cast to each of these actor types to obtain a valid pointer, that I can pass to the TScriptInterface constructor.

Am I missing something here, or is this simply not possible? The way I’m doing it right now, is that I use raw interface pointers, and simply cast to AActor* when passing the pointer to an RPC and then cast back to the interface type on the server (which obviously isn’t optimal, since I’m losing the type safety of the interface type).

Thanks in advance! Cheers, Elewyth

You should just be able to do this:

TScriptInterface<IMyInterface1> x;
TScriptInterface<IMyInterface2> y = Cast<IMyInterface2>(x.GetObject());

… which is even shorter than what you’d like to be able to write! :slight_smile:

Steve

Thanks! I’ll try it, as soon as I get home. Unfortunately, I will not be able to accept your answer, since you posted it as a comment :frowning:

Once you verify that it’s what you’re after, I can convert the comment to an answer.

Steve

Unfortunately your solution does not seem to work :frowning: - I get the following compile error:

C:\Program Files\Epic Games\4.6\Engine\Source\Runtime\CoreUObject\Public\UObject\ScriptInterface.h(144): error C2664: 'void FScriptInterface::SetObject(UObject *)' : cannot convert argument 1 from 'IMyInterface2 *' to 'UObject *'
Types pointed to are unrelated; conversion requires reinterpret_cast, C-style cast or function-style cast
          C:\Program Files\Epic Games\4.6\Engine\Source\Runtime\CoreUObject\Public\UObject\ScriptInterface.h(126) : see reference to function template instantiation 'InterfaceType &TScriptInterface<InterfaceType>::operator =<UObjectType>(UObjectType *)' being compiled
          with
          [
              InterfaceType=IMyInterface2
  ,            UObjectType=IMyInterface2
          ]

That’s odd, my last reply didn’t appear. Yeah, I realised that earlier and posted this alternate solution which at least doesn’t involve an intermediate type:

template <typename To, typename From>
TScriptInterface<To> CastScriptInterface(const TScriptInterface<From>& Interface)
{
    TScriptInterface<To> Result;
    To* Temp = Cast<To>(&*Interface);
    Result.SetInterface(Temp);
    Result.SetObject(Cast<UObject>(Temp));
    return Result;
}

TScriptInterface<IMyInterface1> x;
auto y = CastScriptInterface<IMyInterface2>(x);

But I’ve raised a ticket to improve TScriptInterface as it’s quite deficient in a number of areas.

Steve

Thanks a lot! I’ll consider using this workaround. And yeah, some love for TScriptInterface would be really nice.

Cheers, Elewyth

Is TScriptInterface still on the list for getting some love? Trying to pass a TScriptInterface pointer as a parameter is disturbing as it always fails with the same error message as the OP (cannot convert from IInterface* to UObject*). Having to manually setup the TScriptInterface to pass an interface pointer around is just not very nice. I pass my interface pointers like so:

void IComponentEventListener::SomeFunction()
{
	// Prevents the cast to UObject* error
	TScriptInterface<IComponentEventListener> TS;
	TS.SetObject(Cast<UObject>(this));
	TS.SetInterface(this);

	SomeClassObj->TalkToMe(TS);

	// What I would really like to see is:
	SomeClassObj->TalkToMe(this);
}

void SomeClass::TalkToMe(TScriptInterface<IComponentEventListener> EvL)
{
}

Anyways, I hope there will be more transparency with interfaces in the near future.

2 Likes

I am sad to see this error still exists seven years later in identical fashion.

Interfaces in Unreal are truly some of the most painful contortions that I have had to code around.

2 Likes