【发布时间】:2014-04-06 14:21:33
【问题描述】:
我一直在尝试想出一个轻量级的类,它可以委托静态/成员函数、函子、闭包等。在我的项目中,有必要将这些实体作为函数参数传递,此外,它被使用在其他一些情况下。
第一次,我决定使用模板和继承,结果是这样的:
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表达式的要求。所以我的问题是:这很神奇吗?或者它适用于大多数编译器?
【问题讨论】:
-
自始至终都是未定义的行为。
-
你为什么不直接使用 std::function?
-
没有
delete的new数量太高了.. -
@ChristianHackl 我只是一名学生,这是我的任务。不幸的是,我应该避免使用 STL。 :)
-
@CantChooseUsernames 已修复。无论如何,这并不能改变事实。