我需要像std :: function这样的东西,但后来我发现this更快(正如作者声称的那样),甚至可以通过==运算符进行比较。我改编它以允许动态返回类型和参数,如下所示:
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 Delegate的<TReturn(TArgs...)>
部分到底是什么,为什么我们需要首先定义class Delegate {};
?
答案 0 :(得分:2)
是的,所以经过几天的研究,开发和测试,我制作了一些能够以更好的语法实现更快std::function/std::bind
的东西。
对于那些想知道的人,请看Delegator。我无法粘贴整个代码,因为它太大了,无法在此处发布。此外,在此链接中,您将始终拥有最新版本。
使用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
答案 1 :(得分:0)
基本上,你的语法解决方案是接近我们为实现std::function
所做的工作,并牺牲灵活性的速度(由于使用运行时多态而不是纯模板)
第一个调用可以通过向Delegate
类添加另一个成员变量来解决,以保存自由函数:
template<typename TReturn, typename... TArgs>
class Delegate<TReturn(TArgs...)> final
{
// ...
typedef TReturn(*FreeFunctionType)(TArgs...);
FreeFunctionType m_free_function = nullptr;
};
现在,您可以在m_free_function
内设置specialReset
,同时重置其他成员:
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();
}
第二个有点棘手。
解决这个问题的想法是声明一个抽象的基类指针,我们可以在以后派生它来进行调用:
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
的实现:
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
lambdas(......)。