Как создать несколько функций динамически в C ++? - PullRequest
0 голосов
/ 09 октября 2019

Как видно из заголовка, я хочу динамически создавать функции: время выполнения или время компиляции . Скажем, например, создать 1000 функций. Это скучное копирование и переименование. Скажем, например, следующее:


function myname0001(args){
    struct somevariable0001;
    ...
}
function myname0002(args){
    struct somevariable0002;
    ...
}
function myname0003(args){
    struct somevariable0003;
    ...
}
...
function myname1000(args){
    struct somevariable1000;
    ...
}

, так что, как видите, функция и переменная последовательно изменяются.

Хотя легко вызывать одну функцию тысячу раз, на самом деле существует проблема со сторонней библиотекой, которая этого не позволяет. Итак, как мне создать это последовательное число функций и некоторые их переменные?

Я забыл упомянуть, что это в Linux. GCC8 c11 компилятор

1 Ответ

1 голос
/ 09 октября 2019

Вы можете использовать шаблоны для генерации фиксированного количества функций стиля c во время компиляции, каждая из которых может передавать жестко заданный аргумент в ваш обратный вызов C ++. Вы можете использовать этот жестко заданный аргумент, чтобы связать обратный вызов в стиле c с объектом.

Вот минимальный рабочий пример C ++ 14, который позволяет связать уникальный C ++ std::function с каждым из сгенерированныхОбратный вызов в стиле CВы можете инициализировать std::function с помощью лямбды, которая фиксирует любое нужное вам состояние в этом конкретном обратном вызове:

#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);
}

Решение требует использования глобального состояния, которое здесь равно Callbacks::instance. Альтернативой может быть параметризация c_style_callback со ссылкой на объект со связью (внутренней или внешней), что означает глобальный статический объект с областью имен или классом.

Если вы используете C ++ 11вам нужно будет использовать обратный порт std::integer_sequence и std::make_integer_sequence, который поступил в C ++ 14, но на самом деле не требует каких-либо специфических для C ++ 14 функций. Пример [m = n++] именованные захваты также доступны с C ++ 14, но это только для демонстрации.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...