Может шаблон шаблона c ++ заменить постоянно растущий союз? - PullRequest
1 голос
/ 01 апреля 2020

У меня есть простой класс, который позволяет прерыванию (или другой подпрограмме) планировать запуск функции в следующем проходе основного кода l oop. Это работает с использованием union для описания различных возможных шаблонов аргументов.

Как и для добавления нового типа шаблона аргумента требуется

  1. Добавление typedef для шаблона .
  2. Добавление struct в объединение для представления аргументов.
  3. Добавление объявления и функции addDooer для обработки добавления.
  4. Обновление loop оператор переключения кода для обработки нового типа шаблона.

Образ работы для каждого нового шаблона аргумента. Я просто изучаю шаблоны и мне интересно, можно ли переписать этот класс для использования шаблонов, чтобы упростить добавление дополнительных шаблонов аргументов? И если да, могут ли шаблоны быть расширены, чтобы разрешить и другое количество аргументов?

typedef void (*looper_runner1)(uint32_t arg1, uint16_t arg2);
typedef void (*looper_runner2)(uint8_t *arg1, uint16_t arg2);

struct LoopDooer
{
    uint16_t type;
    union {
        struct
        {
            uint32_t arg1;
            uint16_t arg2;
            looper_runner1 fn;
        } type1;
        struct
        {
            uint8_t *arg1;
            uint16_t arg2;
            looper_runner2 fn;
        } type2;
    } dooer;
};

class Looper
{

public:

    Looper();
    bool addDooer(looper_runner1 fn, uint32_t arg1, uint16_t arg2);
    bool addDooer(looper_runner2 fn, uint8_t *arg1, uint16_t arg2);
    void loop();

private:
    /* ... actual methods not relevant to question */
};

bool Looper::addDooer(looper_runner1 fn, uint32_t arg1, uint16_t arg2)
{
    LoopDooer *p = new LoopDooer();
    p->type = 1;
    p->dooer.type1.fn = fn;
    p->dooer.type1.arg1 = arg1;
    p->dooer.type1.arg2 = arg2;
    return _add(p);
}

bool Looper::addDooer(looper_runner2 fn, uint8_t *arg1, uint16_t arg2)
{
    LoopDooer *p = new LoopDooer();
    p->type = 2;
    p->dooer.type2.fn = fn;
    p->dooer.type2.arg1 = arg1;
    p->dooer.type2.arg2 = arg2;
    return _add(p);
}

// To be called from main loop
void Looper::loop()
{
    LoopDooer *p;

    /* some code removed that just gets next LoopDooer into pointer p */

    // Do it
    switch (p->type)
    {
    case 1:
        p->dooer.type1.fn(p->dooer.type1.arg1, p->dooer.type1.arg2);
        break;
    case 2:
        p->dooer.type2.fn(p->dooer.type2.arg1, p->dooer.type2.arg2);
        break;
    }
    // Delete it
    delete p;
}

1 Ответ

3 голосов
/ 01 апреля 2020

Все, что вы пытаетесь сделать здесь, может быть сделано с std::function и лямбдами напрямую. Они реализуют все логики c, которые вы хотите, для произвольных типов аргументов.

#include<functional>

using LoopDooer = std::function<void()>;

template<typename F, typename... Args>
bool Looper::addDooer(F f, Args&&... args) {
    return _add([=]{ f(args...); });
}

void Looper::loop() {
    LoopDooer dooer = /* extract LoopDoer from container */;
    dooer();
}

Также обратите внимание, что ручное управление памятью с помощью new / delete - плохая идея. По крайней мере, используйте std::unqiue_ptr, но вам вообще не нужно динамическое распределение c. Какой бы контейнер вы не использовали, он, вероятно, должен содержать LoopDooer s напрямую.

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