How to make C++ member variable that holds Blueprint function?

Is there a way in a C++ UObject subclass to create a UPROPERTY(or something) member variable that has a function type and can be assigned a Blueprint function, and called from C++?

Like say I want to have a function that takes an int as input and returns an int as output.

In standard C++ I can write this like std::function<int(int)>.

But I assume the following wouldn’t work, right?

    UPROPERTY(EditAnywhere, BlueprintReadWrite)
    std::function<int(int)> MyFunction;

Is there a way to do that with some other Unreal type in lieu of std::function ?

1 Like

You are looking for a UFUNCTION, not a UPROPERTY.

Can be executed and implemented in Blueprint, has no c++ Implementation:

UFUNCTION(BlueprintCallable, BlueprintImplementableEvent)
    int32 GetSomeIntegerValue(int32 InValue);

Can be executed and implemented in Blueprint, has also a c++ Implementation:

UFUNCTION(BlueprintCallable, BlueprintNativeEvent)
    int32 GetSomeIntegerValue(int32 InValue);

int32 GetSomeIntegerValue_Implementation(int32 InValue);

references:

2 Likes

In addition to what @Roy_Wierer.Seda145 suggested, there are also delegates. This takes a few steps.

First, you need to declare the type. There are macros that all look like:

DECLARE_DYNAMIC_MULTICAST_DELEGATE( FDelegateName )
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam( FDelegateName, Param1Type, Param1Name)

There’s a bunch of these with various parameter counts and versions that allow return types.

Then you can declare a UPROPERTY as

UPROPERTY(BlueprintAssignable)
FDelegateName Delegate;

which you can assign to it in blueprint.

If you’re trying to delegate to blueprint and it’s meant to be something provided by a blueprint derived from your native class, you should probably use Seda’s suggestion. On the other hand if you’ve got something that is meant to inform other objects, like widget events, delegates are the way to go.

There’s a lot more to delegates and what you can do with them, but this should hopefully get you started.

2 Likes

I agree – I think the multicast delegate is a better match for what OP requests than simply a function you must override. Delegates allow binding to whatever event/function in whatever target you want to call, without messing with subclassing the sending class.

1 Like

Interesting. It’s not entirely clear to me what the differences between…

UFUNCTION(BlueprintCallable, BlueprintImplementableEvent)
int32 MyFunction(int32 MyParam);

and

DECLARE_DELEGATE_RetVal_OneParam(int32, FMyFunction, int32);

/*...*/

FMyFunction MyFunction;

…are. I guess the latter can be rebound at runtime whereas the former cannot? And the former must be implemented in a Blueprint subclass whereas the latter can be bound to anything?

1 Like

Basically. You can think of a BlueprintImplementableEvent or BlueprintNativeEvent function as the equivalent to a virtual function and a delegate as just alternate version of std::function.

There are some restrictions to what can be bound to Dynamic Delegates (they can only be bound to UFUNCTIONs).

That is correct. A _DELEGATE_ is generally like a function pointer member, and a UFUNCTION(BlueprintImplementableEvent) is like a virtual function.

Function pointer members, or in this case, delegates, are better from the point of view of the implementing class itself, because it allows arbitrary other classes to hook in, without any further code changes.

In general, virtual functions are bad to express variation points for the declaring class – their main benefit is in expressing behavior to be used by OTHER classes, as when used by interfaces. Implementation inheritance where implementing classes have to call up to parent classes, and where you have to subclass to implement variation, was thought to be a great idea in the 90s when C++ was first made, but has turned out to frequently lead to poor structure in practice. (This is one reason that modern C++ tends to prefer templates and composition, btw.)
That doesn’t mean that you can’t build fine products using implementation inheritance and overridden virtual functions, just that you typically end up paying more doing so (human time, as well as computer time.)

I don’t know what you mean by it frequently lead to poor structure in practice? In what way?

If I understand you correctly, what you are suggesting is that:

    class Animal { public: virtual void speak() = 0; };
    class Dog : Animal { public: void speak() override { print("woof"); }};

is ok, but:

class Animal {
    public: void speak() { print("the animal says"); speak_impl(); }
    protected: virtual void speak_impl() = 0;
};
class Dog : Animal { protected: void speak_impl() override { print("woof"); }};

is not ok - right?

Why is the first ok but not the second? Why does the second lead to poor structure? (or is that not what you mean by “implementation inheritance” ?)

1 Like

This is a bigger topic, and has been subject of some C++con talks and such :slight_smile:

In brief, implementation inheritance ends up losing for two main reasons:

  1. You have to actually subclass to vary whatever it is you want to vary. Subclassing is fragile to any change in any of the superclasses.

  2. Figuring out where something is defined becomes really hard, and making sure that all the child classes call Super::whatever() at the right times ends up being really hard.

Composition (for “hard coupling”) and loose binding (for “runtime coupling”) end up being more maintainable, because they physically separate the design of the “sender” from the design of the “receiver.”
If you don’t like hard-core std::bind type function binding, a pure abstract base class is a nice middle road, where the expectations are all laid out in a clear list of functions, but whoever “does the thing” (implements the PABC) is not otherwise coupled to the implementation of whover “says to do the thing” (the owner/caller of the interface.)

1 Like