【问题标题】:Tricky callback realization (C++)棘手的回调实现(C++)
【发布时间】: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?
  • 没有deletenew数量太高了..
  • @ChristianHackl 我只是一名学生,这是我的任务。不幸的是,我应该避免使用 STL。 :)
  • @CantChooseUsernames 已修复。无论如何,这并不能改变事实。

标签: c++ c++11 lambda closures


【解决方案1】:

您的代码存在生命周期问题:您必须考虑对象有效的范围(以及在此范围之后它们是死的)。

template<class Func>
callback(Func function) {
    auto invoker = [function] (Args ...args) -> ReturnType {
        return function(args...);
    };

    _invoker = &invoker;
}

invoker 捕获状态,因此不能转换为函数指针。如果_invoker 被输入为Function,编译器可能会警告你。

第二次重载的备注相同。

所以,如果它起作用了,那是偶然的。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-12-20
    • 2011-01-26
    • 2021-05-23
    • 1970-01-01
    • 2012-09-02
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多