Для вызова требуется быть stati c в шаблоне класса C ++ - PullRequest
1 голос
/ 01 апреля 2020

Я хотел бы иметь следующую настройку класса в программе:

  • Класс, который реализует буфер. При заполнении этого буфера будет создан поток, который выполняет обратный вызов для обработки действий с полным буфером.
  • Шаблон базового класса, который включает объект буфера. Реализует функцию обратного вызова, которая выполняет вызов виртуальной функции, определенной в производном классе.
  • Производный класс, который наследуется от базового класса и реализует, что делать с данными.

Во-первых, минимальный воспроизводимый пример:

#include <vector>
#include <iostream>
#include <thread>

template <typename T>
class CallbackBuffer
{
    public:

        std::vector<T> buffer;
        void (*callback)(std::vector<T>);
        std::thread writerThread;

        CallbackBuffer(int bufferSize = 10)
        {
            buffer.resize(bufferSize);
        }

        void setCallback(void (*cb)(std::vector<T>))
        {
            callback = cb;
        }

        void writeCall()
        {
            writerThread = std::thread(callback, buffer);
        }
};

template <typename T>
class Base
{
    public:

        CallbackBuffer<T> buffer;

        Base()
        {
            buffer.setCallback(bufferHandler);
        }

        void bufferHandler(std::vector<T> v)
        {
            for(auto &i : v)
            {
                write(i);
            }
        }

        virtual void write(T i) = 0;
};

class Derived : public Base<int>
{
    public:

        Derived()
        {
        }

        void write(int i)
        {
            std::cout << i << std::endl;
        }
};

int main()
{
    Derived d;
    return 0;
}

Я получаю следующую ошибку компилятора:

error: invalid use of non-static member function ‘void Base<T>::bufferHandler(std::vector<T>) [with T = int]’

Таким образом, компилятору необходимо bufferHandler , чтобы быть stati c, но если бы я это сделал, у меня не было бы доступа к членам объекта. Есть ли способ разобраться в этом, или просто ужасная идея?

Ответы [ 2 ]

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

Вы передаете функцию-член класса, поэтому вам необходимо иметь в вашем CallbackBuffer классе что-то вроде:

void (Base<T>::*callback)(std::vector<T>);

// ...

void setCallback(void (Base<T>::*cb)(std::vector<T>)) {
    callback = cb;
}

и в Base классе:

Base() {
    buffer.setCallback(&Base<T>::bufferHandler);
}

Демо

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

Указатели на функции-члены имеют тип, отличный от обычных функций, поэтому ваш код не работает. Возможно, вы захотите использовать std::function вместо необработанных указателей:

#include <functional>

//...
std::function<void(std::vector<T>)> callback;

// ...

void setCallback(const std::function<void(std::vector<T>)>& cb) {
    callback = cb;
}

и передать его следующим образом:

Base() {
    buffer.setCallback([this](auto& vec){ this->bufferHandler(vec); });
}

ИМХО, это гораздо более читабельно и гибко, чем передача элемента указатели

...