我一直在想一个轻量级的类,它可以委托(delegate)静态/成员函数、仿函数、闭包等。在我的项目中,需要将这些实体作为函数参数传递,此外,还使用了this在其他一些情况下。
第一次,我决定使用模板和继承,结果是这样的:
template<class ReturnType, class ...Args>
class callback {
private:
//
struct abstract_invoker {
virtual ReturnType invoke(Args...) = 0;
};
//
template<class Function>
class sf_invoker : public abstract_invoker {
public:
sf_invoker(Function function) : _function(function) { };
ReturnType invoke(Args ...args) override {
return _function(args...);
}
private:
Function _function;
};
//
template<class Class>
class mf_invoker : public abstract_invoker {
using Function = ReturnType (Class::*)(Args...);
public:
mf_invoker(Class& target, Function function) : _target(target), _function(function) { };
ReturnType invoke(Args ...args) override {
return (_target.*_function)(args...);
}
private:
Class& _target;
Function _function;
};
// --------------------------------------
public:
template<class Function>
callback(Function function) {
_invoker = new sf_invoker<Function>(function);
}
template<class Class>
callback(Class& object, ReturnType(Class::*function)(Args...)) {
_invoker = new mf_invoker<Class>(object, function);
}
~callback() {
delete _invoker;
}
ReturnType operator() (Args ...args) {
return _invoker->invoke(args...);
}
private:
abstract_invoker* _invoker;
};
其实这个方法解决了我的问题,只是速度有点慢。我试图避免虚函数,根据经验发现下面的代码也能正常工作 (VS 2014):
template<class ReturnType, class ...Args>
class callback {
using Function = ReturnType (*)(Args...);
public:
template<class _Function>
callback(_Function function) {
auto invoker = [function] (Args ...args) -> ReturnType {
return function(args...);
};
_invoker = &invoker;
}
template<class _Class>
callback(_Class& object, ReturnType (_Class::*function)(Args...)) {
auto invoker = [function, &object] (Args ...args) -> ReturnType {
return (object.*function)(args...);
};
_invoker = &invoker;
}
ReturnType operator()(Args ...args) {
return (*(Function*) _invoker)(args...);
}
private:
void* _invoker;
};
显然,此实现的运行速度更快。这样的方法是不安全的,但我不是很了解标准,所以我不知道lambda表达式的编译器要求。所以我的问题是:它有魔法吗?还是它适用于大多数编译器?
最佳答案
您的代码存在生命周期问题:您必须考虑对象有效的范围(以及之后它们就死了)。
template<class Func>
callback(Func function) {
auto invoker = [function] (Args ...args) -> ReturnType {
return function(args...);
};
_invoker = &invoker;
}
invoker
捕获状态,因此不能转换为指向函数的指针。如果 _invoker
被键入为 Function
,编译器可能会警告您。
第二次重载同上。
所以,如果它起作用,那是偶然的。
关于c++ - 棘手的回调实现(C++),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22895300/