繁体   English   中英

在 c++ 中以编程方式创建函数

[英]Programmatically creating functions in c++

假设我们有一个包含 1000 个 function 副本的代码,格式如下:

function myname_[X](args){
    struct somevariable_[X];
    //others
}

其中 [X] 是一个序列,例如 0001、0002 等。

我打算通过以编程方式生成 function 和变量名称来使其更清晰。 我们如何在 c++ 中做到这一点?

您可以使用模板生成编译时固定数量的 c 样式函数,每个函数都可以将硬编码参数传递给 C++ 回调。 您可以使用该硬编码参数将 c 样式回调与 object 相关联。

这是一个最小的工作 C++14 示例,它允许将唯一的 C++ std::function与每个生成的 c 样式回调相关联。 您可以使用 lambda 来初始化std::function ,该 lambda 捕获您在该特定回调中需要的任何 state :

#include <iostream>
#include <algorithm>
#include <functional>

class Callbacks {
    static constexpr unsigned count = 1000;
    static Callbacks* instance;

    using CF = void(); // C-style callback type.
    using F = std::function<CF>; // C++ stateful callback type.

    F callbacks_[count];
    CF* c_style_callbacks_[count];

    template<unsigned Index>
    static void c_style_callback() {
        instance->callbacks_[Index]();
    }

    template<unsigned... Index>
    void make_c_style_callbacks(std::integer_sequence<unsigned, Index...>) {
        auto initializer_list = {(c_style_callbacks_[Index] = &c_style_callback<Index>)...};
        static_cast<void>(initializer_list);
    }

public:
    Callbacks() {
        make_c_style_callbacks(std::make_integer_sequence<unsigned, count>{});
        if(instance)
            throw; // One instance only please.
        instance = this;
    }

    Callbacks(Callbacks const&) = delete;
    Callbacks& operator=(Callbacks const&) = delete;

    ~Callbacks() noexcept {
        instance = 0;
    }

    CF* register_callback(F f) noexcept {
        // Linear search can be improved upon.
        auto condition = [](F const& f) { return !f; };
        auto index = std::find_if(std::begin(callbacks_), std::end(callbacks_), condition) - std::begin(callbacks_);
        if(index < count) {
            callbacks_[index] = std::move(f); // Assumes move-assignement is noexcept.
            return c_style_callbacks_[index];
        }
        return 0;
    }

    void unregister_callback(CF* cf) noexcept {
        // Linear search can be improved upon.
        auto index = std::find(std::begin(c_style_callbacks_), std::end(c_style_callbacks_), cf) - std::begin(c_style_callbacks_);
        if(index < count)
            callbacks_[index] = {};
        else
            throw; // cf has not been found. Programming error.
    }
};

Callbacks* Callbacks::instance = 0;

int main() {
    Callbacks c;
    unsigned n = 0;

    auto p0 = c.register_callback([m = n++]() { std::cout << m << '\n'; });
    auto p1 = c.register_callback([m = n++]() { std::cout << m << '\n'; });
    auto p2 = c.register_callback([m = n++]() { std::cout << m << '\n'; });

    p0(); // Outputs 0.
    p1(); // Outputs 1.
    p2(); // Outputs 2.

    c.unregister_callback(p2);
    c.unregister_callback(p1);
    c.unregister_callback(p0);
}

该解决方案需要使用一点全局 state,这里是Callbacks::instance An alternative would be to parametrize c_style_callback with a reference to an object with linkage (internal or external), which means a global, namespace-scoped or class static object.

如果您使用的是 C++11,您将需要使用到达 C++14 但实际上不需要任何 C++14 特定功能的std::integer_sequencestd::make_integer_sequence的反向移植。 自 C++14 起,示例[m = n++]命名捕获也可用,但这仅用于演示。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM