免费和成员函数的自定义 std::function-like 实现
Custom std::function-like implementation for both free and member functions
我需要像 std::function 这样的东西,但后来我发现 this 更快(正如作者所说),甚至可以用 == 运算符进行比较。我对其进行了调整以允许动态 return 类型和参数,如下所示:
template<typename TReturn, typename... TArgs>
class Delegate {};
template<typename TReturn, typename... TArgs>
class Delegate<TReturn(TArgs...)> final
{
private:
typedef void* InstancePointer;
typedef TReturn (*InternalFunction)(InstancePointer, TArgs...);
private:
// Turns a free function into our internal function stub
template <TReturn (*FreeFunction)(TArgs...)>
static TReturn FreeFunctionStub(InstancePointer instance, TArgs... args) {
// We don't need the instance pointer because we're dealing with free functions
return (FreeFunction)(std::forward<TArgs>(args)...);
}
// Turns a member function into our internal function stub
template <class TClass, TReturn (TClass::*MemberFunction)(TArgs...)>
static TReturn MemberFunctionStub(InstancePointer instance, TArgs... args) {
// Cast the instance pointer back into the original class instance
return (static_cast<TClass*>(instance)->*MemberFunction)(std::forward<TArgs>(args)...);
}
public:
Delegate() = default;
// Resets this delegate to a new free function
template <TReturn(*FreeFunction)(TArgs...)>
void reset() {
m_instance = nullptr;
m_function = &FreeFunctionStub<FreeFunction>;
}
// Resets this delegate to a new member function
template <class TClass, TReturn(TClass::*MemberFunction)(TArgs...)>
void reset(TClass* instance) {
m_instance = instance;
m_function = &MemberFunctionStub<TClass, MemberFunction>;
}
// Resets this delegate to a new free function
void specialReset(TReturn(*FreeFunction)(TArgs...)) {
m_instance = nullptr;
m_function = ???
}
// Resets this delegate to a new member function
template<class TClass>
void specialReset(TClass *instance, TReturn(TClass::*MemberFunction)(TArgs...)) {
m_instance = instance;
m_function = ???
}
// Invokes this delegate
TReturn invoke(TArgs... args) const {
if (m_function == nullptr)
throw new std::runtime_error(""Unbound delegate! Call reset() first."");
return m_function(m_instance, std::forward<TArgs>(args)...);
}
private:
InstancePointer m_instance;
InternalFunction m_function;
};
用法是这样的:
Delegate<void()> del1;
Delegate<int(double)> del2;
del1.reset<&someParameterlessVoidFreeFunction>();
del1.invoke();
del2.reset<SomeClass, &SomeClass::someIntMemberFunction>(&someClassInstance);
del2.invoke(24.2);
我想做的是实现这样的目标(IMO,更简洁直观):
Delegate<void()> del1;
Delegate<int(double)> del2;
del1.reset(&someParameterlessVoidFreeFunction);
del1.invoke();
del2.reset(&SomeClass::someIntMemberFunction, &someClassInstance);
del2.invoke(24.2);
不过,我不太明白m_function
这个概念。我想要达到的目标甚至是可能的?我怎么能那样做?
此外,class 委托的 <TReturn(TArgs...)>
部分到底是什么?为什么我们需要先定义一个 class Delegate {};
?
基本上,您的语法的解决方案是更接近我们为实现 std::function
所做的事情并牺牲速度以获得灵活性(由于使用 run-time 多态性而不是纯模板)
可以通过向 Delegate
class 添加另一个成员变量来保存自由函数来解决第一个调用:
template<typename TReturn, typename... TArgs>
class Delegate<TReturn(TArgs...)> final
{
// ...
typedef TReturn(*FreeFunctionType)(TArgs...);
FreeFunctionType m_free_function = nullptr;
};
现在您可以在 specialReset
内设置 m_free_function
,同时重置其他成员:
void specialReset(TReturn(*FreeFunction)(TArgs...)) {
m_instance = nullptr;
m_function = nullptr;
m_free_function = FreeFunction;
}
并调用它执行额外的空检查:
TReturn invoke(TArgs... args) const {
if (m_function == nullptr && m_free_function == nullptr)
throw new std::runtime_error("Unbound delegate! Call reset() first.");
else if (m_function)
return m_function(m_instance, std::forward<TArgs>(args)...);
else return m_free_function(std::forward<TArgs>(args)...);
}
和一个测试:
void foo()
{
std::cout << "Called foo()\n";
}
int main()
{
Delegate<void()> del1;
del1.specialReset(&::foo);
del1.invoke();
}
第二个有点棘手。
解决这个问题的想法是声明一个抽象基 class 指针,我们可以从中派生稍后进行调用:
template<typename TReturn, typename... TArgs>
class Delegate<TReturn(TArgs...)> final
{
private:
//...
struct ICall
{
virtual TReturn doCall(TArgs... args) = 0;
};
std::unique_ptr<ICall> caller;
};
通常这个指针是nullptr
,我们可以检查,否则我们可以调用invoke
中的函数:
// Invokes this delegate
TReturn invoke(TArgs... args) const {
if (m_function == nullptr && m_free_function == nullptr && caller == nullptr)
throw new std::runtime_error("Unbound delegate! Call reset() first.");
else if (m_function)
return m_function(m_instance, std::forward<TArgs>(args)...);
else if (caller)
return caller->doCall(std::forward<TArgs>(args)...);
else
return m_free_function(std::forward<TArgs>(args)...);
}
最后是我们第二个 specialReset
的实现,我们创建一个派生 class 并设置我们的指针:
template<class TClass>
void specialReset(TClass *instance, TReturn(TClass::*MemberFunc)(TArgs...)) {
m_instance = nullptr;
m_function = nullptr;
m_free_function = nullptr;
struct DerivedCall : public ICall
{
DerivedCall(TClass* _instance, TReturn(TClass::*_func)(TArgs...)) : m_instance(_instance), m_func(_func){}
TReturn doCall(TArgs... args) override
{
return (m_instance->*m_func)(std::forward<TArgs>(args)...);
}
TClass* m_instance;
TReturn(TClass::*m_func)(TArgs...);
};
caller = std::make_unique<DerivedCall>(instance, MemberFunc);
}
还有一个测试:
struct A{
int foo(double){std::cout << "Called A::foo\n"; return 42;}
};
int main()
{
Delegate<int(double)> del2;
A a;
del2.specialReset(&a, &A::foo);
del2.invoke(24.2);
}
我相信比我聪明的人一定能想出更好的办法。就像我说的。由于这一切的运行时间,我们可能已经失去了您提倡的超过 std::function
的宝贵速度,而且我不确定它对 operator==
做了什么(第二次可能变得不可行我创建了 m_free_function
)。我们不能在此处将 specialReset
与 lambda 一起使用(...还)。
是的,经过几天的研究、开发和测试,我编造了一些确实可以更快 std::function/std::bind
且语法更好的东西。
对于那些想知道的人,请看一看 Delegator。我不能在这里粘贴整个代码,因为它太大了,无法在这里发布。此外,在此 link 您将始终拥有最新版本。
使用 Delegator,您可以执行以下操作:
Delegate<void(void)> d1; // Blank delegate
Delegate<void(void)> d2(&freeFunction); // Delegate to a free function
Delegate<void(void)> d3(&SomeClass::someClassStaticFunction); // Delegate to a static function
Delegate<void(void)> d4(&SomeClass::someClassFunction, &someClassInstance); // Delegate to a member function
Delegate<void(void)> d5(&SomeClass::someClassConstFunction, &someClassInstance); // Delegate to a member const function
d1.reset(); // Resets the delegate
d1.reset(&freeFunction); // Resets the delegate to a free function
d1.reset(&SomeClass::someClassStaticFunction); // Resets the delegate to a static function
d1.reset(&SomeClass::someClassFunction, &someClassInstance); // Resets the delegate to a member function
d1.reset(&SomeClass::someClassConstFunction, &someClassInstance); // Resets the delegate to a member const function
d1.reset(&d2); // Resets the delegate to d2's state
我需要像 std::function 这样的东西,但后来我发现 this 更快(正如作者所说),甚至可以用 == 运算符进行比较。我对其进行了调整以允许动态 return 类型和参数,如下所示:
template<typename TReturn, typename... TArgs>
class Delegate {};
template<typename TReturn, typename... TArgs>
class Delegate<TReturn(TArgs...)> final
{
private:
typedef void* InstancePointer;
typedef TReturn (*InternalFunction)(InstancePointer, TArgs...);
private:
// Turns a free function into our internal function stub
template <TReturn (*FreeFunction)(TArgs...)>
static TReturn FreeFunctionStub(InstancePointer instance, TArgs... args) {
// We don't need the instance pointer because we're dealing with free functions
return (FreeFunction)(std::forward<TArgs>(args)...);
}
// Turns a member function into our internal function stub
template <class TClass, TReturn (TClass::*MemberFunction)(TArgs...)>
static TReturn MemberFunctionStub(InstancePointer instance, TArgs... args) {
// Cast the instance pointer back into the original class instance
return (static_cast<TClass*>(instance)->*MemberFunction)(std::forward<TArgs>(args)...);
}
public:
Delegate() = default;
// Resets this delegate to a new free function
template <TReturn(*FreeFunction)(TArgs...)>
void reset() {
m_instance = nullptr;
m_function = &FreeFunctionStub<FreeFunction>;
}
// Resets this delegate to a new member function
template <class TClass, TReturn(TClass::*MemberFunction)(TArgs...)>
void reset(TClass* instance) {
m_instance = instance;
m_function = &MemberFunctionStub<TClass, MemberFunction>;
}
// Resets this delegate to a new free function
void specialReset(TReturn(*FreeFunction)(TArgs...)) {
m_instance = nullptr;
m_function = ???
}
// Resets this delegate to a new member function
template<class TClass>
void specialReset(TClass *instance, TReturn(TClass::*MemberFunction)(TArgs...)) {
m_instance = instance;
m_function = ???
}
// Invokes this delegate
TReturn invoke(TArgs... args) const {
if (m_function == nullptr)
throw new std::runtime_error(""Unbound delegate! Call reset() first."");
return m_function(m_instance, std::forward<TArgs>(args)...);
}
private:
InstancePointer m_instance;
InternalFunction m_function;
};
用法是这样的:
Delegate<void()> del1;
Delegate<int(double)> del2;
del1.reset<&someParameterlessVoidFreeFunction>();
del1.invoke();
del2.reset<SomeClass, &SomeClass::someIntMemberFunction>(&someClassInstance);
del2.invoke(24.2);
我想做的是实现这样的目标(IMO,更简洁直观):
Delegate<void()> del1;
Delegate<int(double)> del2;
del1.reset(&someParameterlessVoidFreeFunction);
del1.invoke();
del2.reset(&SomeClass::someIntMemberFunction, &someClassInstance);
del2.invoke(24.2);
不过,我不太明白m_function
这个概念。我想要达到的目标甚至是可能的?我怎么能那样做?
此外,class 委托的 <TReturn(TArgs...)>
部分到底是什么?为什么我们需要先定义一个 class Delegate {};
?
基本上,您的语法的解决方案是更接近我们为实现 std::function
所做的事情并牺牲速度以获得灵活性(由于使用 run-time 多态性而不是纯模板)
可以通过向 Delegate
class 添加另一个成员变量来保存自由函数来解决第一个调用:
template<typename TReturn, typename... TArgs>
class Delegate<TReturn(TArgs...)> final
{
// ...
typedef TReturn(*FreeFunctionType)(TArgs...);
FreeFunctionType m_free_function = nullptr;
};
现在您可以在 specialReset
内设置 m_free_function
,同时重置其他成员:
void specialReset(TReturn(*FreeFunction)(TArgs...)) {
m_instance = nullptr;
m_function = nullptr;
m_free_function = FreeFunction;
}
并调用它执行额外的空检查:
TReturn invoke(TArgs... args) const {
if (m_function == nullptr && m_free_function == nullptr)
throw new std::runtime_error("Unbound delegate! Call reset() first.");
else if (m_function)
return m_function(m_instance, std::forward<TArgs>(args)...);
else return m_free_function(std::forward<TArgs>(args)...);
}
和一个测试:
void foo()
{
std::cout << "Called foo()\n";
}
int main()
{
Delegate<void()> del1;
del1.specialReset(&::foo);
del1.invoke();
}
第二个有点棘手。
解决这个问题的想法是声明一个抽象基 class 指针,我们可以从中派生稍后进行调用:
template<typename TReturn, typename... TArgs>
class Delegate<TReturn(TArgs...)> final
{
private:
//...
struct ICall
{
virtual TReturn doCall(TArgs... args) = 0;
};
std::unique_ptr<ICall> caller;
};
通常这个指针是nullptr
,我们可以检查,否则我们可以调用invoke
中的函数:
// Invokes this delegate
TReturn invoke(TArgs... args) const {
if (m_function == nullptr && m_free_function == nullptr && caller == nullptr)
throw new std::runtime_error("Unbound delegate! Call reset() first.");
else if (m_function)
return m_function(m_instance, std::forward<TArgs>(args)...);
else if (caller)
return caller->doCall(std::forward<TArgs>(args)...);
else
return m_free_function(std::forward<TArgs>(args)...);
}
最后是我们第二个 specialReset
的实现,我们创建一个派生 class 并设置我们的指针:
template<class TClass>
void specialReset(TClass *instance, TReturn(TClass::*MemberFunc)(TArgs...)) {
m_instance = nullptr;
m_function = nullptr;
m_free_function = nullptr;
struct DerivedCall : public ICall
{
DerivedCall(TClass* _instance, TReturn(TClass::*_func)(TArgs...)) : m_instance(_instance), m_func(_func){}
TReturn doCall(TArgs... args) override
{
return (m_instance->*m_func)(std::forward<TArgs>(args)...);
}
TClass* m_instance;
TReturn(TClass::*m_func)(TArgs...);
};
caller = std::make_unique<DerivedCall>(instance, MemberFunc);
}
还有一个测试:
struct A{
int foo(double){std::cout << "Called A::foo\n"; return 42;}
};
int main()
{
Delegate<int(double)> del2;
A a;
del2.specialReset(&a, &A::foo);
del2.invoke(24.2);
}
我相信比我聪明的人一定能想出更好的办法。就像我说的。由于这一切的运行时间,我们可能已经失去了您提倡的超过 std::function
的宝贵速度,而且我不确定它对 operator==
做了什么(第二次可能变得不可行我创建了 m_free_function
)。我们不能在此处将 specialReset
与 lambda 一起使用(...还)。
是的,经过几天的研究、开发和测试,我编造了一些确实可以更快 std::function/std::bind
且语法更好的东西。
对于那些想知道的人,请看一看 Delegator。我不能在这里粘贴整个代码,因为它太大了,无法在这里发布。此外,在此 link 您将始终拥有最新版本。
使用 Delegator,您可以执行以下操作:
Delegate<void(void)> d1; // Blank delegate
Delegate<void(void)> d2(&freeFunction); // Delegate to a free function
Delegate<void(void)> d3(&SomeClass::someClassStaticFunction); // Delegate to a static function
Delegate<void(void)> d4(&SomeClass::someClassFunction, &someClassInstance); // Delegate to a member function
Delegate<void(void)> d5(&SomeClass::someClassConstFunction, &someClassInstance); // Delegate to a member const function
d1.reset(); // Resets the delegate
d1.reset(&freeFunction); // Resets the delegate to a free function
d1.reset(&SomeClass::someClassStaticFunction); // Resets the delegate to a static function
d1.reset(&SomeClass::someClassFunction, &someClassInstance); // Resets the delegate to a member function
d1.reset(&SomeClass::someClassConstFunction, &someClassInstance); // Resets the delegate to a member const function
d1.reset(&d2); // Resets the delegate to d2's state