Trying to bind the function with parameter of pass by reference, and value type payload, makes compile error.
Is this illegal?
It is totally about my curiosity. I can work workaround this, by using a pointer type parameter. But, I want to understand this. I want to get knowledge of why this is happening. I searched for this for three days, but I could not get it.
This code makes a compile error.
This is header file.
//SomeEmptyPlugin.h
#pragma once
#include "CoreMinimal.h"
#include "Modules/ModuleManager.h"
DECLARE_DELEGATE(FSomeDelegate);
struct FSomeStruct
{
public:
int32 SomeValue;
FSomeStruct()
: SomeValue(42)
{}
explicit FSomeStruct(int32 InSomeValue)
: SomeValue(InSomeValue)
{}
};
class FSomeEmptyPluginModule : public IModuleInterface
{
public:
FSomeDelegate DelegateWithoutPayload;
FSomeDelegate DelegateWithValuePayload;
FSomeDelegate DelegateWithPointerPayload;
FSomeDelegate DelegateWithReferencePayload;
FSomeStruct SomeStruct;
void SomeTest();
void FunctionWithoutParameter();
void FunctionWithValueParameter(FSomeStruct SomePayLoad);
void FunctionWithPointerParameter(FSomeStruct* SomePayLoad);
void FunctionWithReferenceParameter(FSomeStruct& SomePayLoad);
/** IModuleInterface implementation */
virtual void StartupModule() override;
virtual void ShutdownModule() override;
};
And this is source file.
//SomeEmptyPlugin.cpp
#include "SomeEmptyPlugin.h"
#define LOCTEXT_NAMESPACE "FSomeEmptyPluginModule"
void FSomeEmptyPluginModule::SomeTest()
{
DelegateWithoutPayload.BindRaw(
this
, &FSomeEmptyPluginModule::FunctionWithoutParameter
);
DelegateWithValuePayload.BindRaw(
this
, &FSomeEmptyPluginModule::FunctionWithValueParameter
, SomeStruct
);
DelegateWithPointerPayload.BindRaw(
this
, &FSomeEmptyPluginModule::FunctionWithPointerParameter
, &SomeStruct
);
DelegateWithReferencePayload.BindRaw(
this
, &FSomeEmptyPluginModule::FunctionWithReferenceParameter
, SomeStruct
); //This is making the compile error!
void (FSomeEmptyPluginModule::*SomeFunctionPtrWithValueParam)(FSomeStruct) = nullptr;
SomeFunctionPtrWithValueParam = &FSomeEmptyPluginModule::FunctionWithValueParameter;
(this->*SomeFunctionPtrWithValueParam)(this->SomeStruct);
void (FSomeEmptyPluginModule::*SomeFunctionPtrWithRefParam)(FSomeStruct&) = nullptr;
SomeFunctionPtrWithRefParam = &FSomeEmptyPluginModule::FunctionWithReferenceParameter;
(this->*SomeFunctionPtrWithRefParam)(this->SomeStruct);
}
void FSomeEmptyPluginModule::FunctionWithoutParameter()
{
UE_LOG(LogTemp, Warning, TEXT("SomeFunction called"));
}
void FSomeEmptyPluginModule::FunctionWithValueParameter
(FSomeStruct SomePayLoad)
{
UE_LOG(LogTemp, Warning, TEXT("SomeLog %d"), SomePayLoad.SomeValue);
}
void FSomeEmptyPluginModule::FunctionWithPointerParameter
(FSomeStruct* SomePayLoad)
{
UE_LOG(LogTemp, Warning, TEXT("SomeLog %d"), SomePayLoad->SomeValue);
}
void FSomeEmptyPluginModule::FunctionWithReferenceParameter
(FSomeStruct& SomePayLoad)
{
UE_LOG(LogTemp, Warning, TEXT("SomeLog %d"), SomePayLoad.SomeValue);
}
void FSomeEmptyPluginModule::StartupModule()
{
SomeTest();
}
void FSomeEmptyPluginModule::ShutdownModule()
{
}
#undef LOCTEXT_NAMESPACE
IMPLEMENT_MODULE(FSomeEmptyPluginModule, SomeEmptyPlugin)
Binding about these works well.
- DelegateWithoutPayload and FunctionWithoutParameter
- DelegateWithValuePayload and FunctionWithValueParameter
- DelegateWithPointerPayload and FunctionWithPointerParameter
But, Binding about this, makes compile error.
- DelegateWithReferencePayload and FunctionWithReferenceParameter
The compile error is like below:
In IDE, I can see this with tooltip.
No viable function. Argument types: FSomeEmptyPluginModule*, void(FSomeEmptyPluginModule::*)(FSomeStruct&), FSomeStruct. Candidates considered: inline void BindRaw<UserClass, VarTypes...>(UserClass* InUserObject, typename TMemFunPtrType<false, UserClass, TDelegate<void()>::RetValType(std::decay_t<VarTypes>...)>::Type InFunc, VarTypes&&...) (in class TDelegate<void(), FDefaultDelegateUserPolicy>) conversion of 2nd argument &FSomeEmptyPluginModule::FunctionWithReferenceParameter is ill-formed: cannot convert void(FSomeEmptyPluginModule::*)(FSomeStruct&) to parameter type TMemFunPtrType<false, FSomeEmptyPluginModule, TDelegate<void()>::RetValType(std::decay_t<FSomeStruct&>)>::Type (aka void(FSomeEmptyPluginModule::*)(FSomeStruct)), because source function and target function have different 1st parameter types: FSomeStruct& and FSomeStruct inline void BindRaw<UserClass, VarTypes...>(const UserClass* InUserObject, typename TMemFunPtrType<true, UserClass, TDelegate<void()>::RetValType(std::decay_t<VarTypes>...)>::Type InFunc, VarTypes&&...) (in class TDelegate<void(), FDefaultDelegateUserPolicy>) conversion of 2nd argument &FSomeEmptyPluginModule::FunctionWithReferenceParameter is ill-formed: cannot convert void(FSomeEmptyPluginModule::*)(FSomeStruct&) to parameter type TMemFunPtrType<true, FSomeEmptyPluginModule, TDelegate<void()>::RetValType(std::decay_t<FSomeStruct&>)>::Type (aka void(FSomeEmptyPluginModule::*)(FSomeStruct) const), because target function has const qualifier
And I can see after trying to compile:
0>SomeEmptyPlugin.cpp(26): Error C2665 : 'TDelegate<void (void),FDefaultDelegateUserPolicy>::BindRaw': no overloaded function could convert all the argument types
0>DelegateSignatureImpl.inl(400): Reference : could be 'void TDelegate<void (void),FDefaultDelegateUserPolicy>::BindRaw<FSomeEmptyPluginModule,FSomeStruct&>(const UserClass *,void (__cdecl FSomeEmptyPluginModule::* )(FSomeStruct) const,FSomeStruct &)'
0> with
0> [
0> UserClass=FSomeEmptyPluginModule
0> ]
0>SomeEmptyPlugin.cpp(26): Reference : 'void TDelegate<void (void),FDefaultDelegateUserPolicy>::BindRaw<FSomeEmptyPluginModule,FSomeStruct&>(const UserClass *,void (__cdecl FSomeEmptyPluginModule::* )(FSomeStruct) const,FSomeStruct &)': cannot convert argument 2 from 'void (__cdecl FSomeEmptyPluginModule::* )(FSomeStruct &)' to 'void (__cdecl FSomeEmptyPluginModule::* )(FSomeStruct) const'
0> with
0> [
0> UserClass=FSomeEmptyPluginModule
0> ]
0>SomeEmptyPlugin.cpp(28): Reference : Types pointed to are unrelated; conversion requires reinterpret_cast, C-style cast or parenthesized function-style cast
0>DelegateSignatureImpl.inl(393): Reference : or 'void TDelegate<void (void),FDefaultDelegateUserPolicy>::BindRaw<FSomeEmptyPluginModule,FSomeStruct&>(UserClass *,void (__cdecl FSomeEmptyPluginModule::* )(FSomeStruct),FSomeStruct &)'
0> with
0> [
0> UserClass=FSomeEmptyPluginModule
0> ]
0>SomeEmptyPlugin.cpp(26): Reference : 'void TDelegate<void (void),FDefaultDelegateUserPolicy>::BindRaw<FSomeEmptyPluginModule,FSomeStruct&>(UserClass *,void (__cdecl FSomeEmptyPluginModule::* )(FSomeStruct),FSomeStruct &)': cannot convert argument 2 from 'void (__cdecl FSomeEmptyPluginModule::* )(FSomeStruct &)' to 'void (__cdecl FSomeEmptyPluginModule::* )(FSomeStruct)'
0> with
0> [
0> UserClass=FSomeEmptyPluginModule
0> ]
0>SomeEmptyPlugin.cpp(28): Reference : Types pointed to are unrelated; conversion requires reinterpret_cast, C-style cast or parenthesized function-style cast
0>SomeEmptyPlugin.cpp(26): Reference : while trying to match the argument list '(FSomeEmptyPluginModule *, void (__cdecl FSomeEmptyPluginModule::* )(FSomeStruct &), FSomeStruct)'
According to my short knowledge of c++, a parameter of the reference type can get value type input. But the codes above does not.
I searched and read again about below in the last three days:
- std::decay_t<>, But this is not the cause. I tried UE 5.1, which is without std::decay_t<>.
- reference collapse
- template type deduction
- move semantics, perfect forwarding, universal references
But those seem not related to, in my seeing.
When this pattern of problems happened to me,
there was a fairly high probability that it was due to my lack of basic knowledge.
What is happening inside there?