Шаблонный класс C ++ с функцией обратного вызова - PullRequest
0 голосов
/ 15 октября 2019

Несмотря на то, что я довольно много читал о шаблонах, я впервые пытаюсь использовать их. Таким образом, моей проблемой может быть просто отсутствие понимания шаблонов.

У меня есть класс, который должен независимо и периодически генерировать некоторые данные. Когда появляются новые данные, он вызывает родителя через функцию обратного вызова и отправляет данные. Предполагается, что класс должен быть переносимым, то есть шаблонным родителем.

Но если я использую шаблон в своем классе данных, я должен перетаскивать шаблон со мной в каждую функцию, и он просто кажется ненужным сложным для того, чтобы быть простов состоянии вызвать одну функцию. Поэтому я создал небольшой класс обратного вызова в глобальном пространстве имен, который хотел использовать в качестве интерфейса.

namespace wrapper
{
    //Callback class
    template<typename ParentClass>
    class Data_Callback
    {
    public:
        ParentClass* m_parent = nullptr;
        Data_Callback<ParentClass>(ParentClass* parent)
        {
            m_parent = parent;
        };

        void DoCallback(DataClass* data)
        {
            if (m_parent)
                m_parent->callback_func(*data);
        }
    };

    //global object I want to use for callback
    template<typename ParentClass>
    std::unique_ptr<Data_Callback<ParentClass>> m_parentCallback;

    template<typename ParentClass>
    PatientenErkennung GetNewDataClass(ParentClass* parent)
    {
        m_parentCallback = std::make_unique<Data_Callback<ParentClass>>(parent);

        std::shared_ptr<DataClass> obj =  std::make_shared<DataClass>();
        return obj;
    };
}

Затем я могу вызвать свою глобальную функцию «GetNewDataClass», как это из моего родительского класса:

m_data = wrapper::GetNewDataClass(this);

Но когда я хочу вызвать обратный вызов из DataClass, шаблон становится таким:

wrapper::m_parentCallback<I_DONT_HAVE_THIS>->DoCallback(data);

Я не могу вызвать этот глобальный объект, не зная родительского класса, могуЯ? Таким образом, обратный вызов может быть инициализирован только из класса Data_Callback, но этот класс не содержит данных.

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

1 Ответ

0 голосов
/ 15 октября 2019

Вам понадобится стирание типа, которое вы можете свернуть вручную. Но стандарт уже предоставляет универсальный интерфейс для функций (включая обратные вызовы) любого вида: std::function (который внутренне выполняет стирание типа, которое вам здесь потребуется).

namespace wrapper
{
    //global object I want to use for callback
    std::function<void(DataClass&)> m_parentCallback;

    template<typename ParentClass>
    auto GetNewDataClass(ParentClass* parent)
    {
        m_parentCallback = [parent](DataClass& dc){ parent->callback_func(dc); };

        std::shared_ptr<DataClass> obj =  std::make_shared<DataClass>();
        return obj;
    };
}

m_parentCallback объявляется какstd::function, который принимает ссылку DataClass и ничего не возвращает. Мы инициализируем его в GetNewDataClass с помощью лямбды, которая фиксирует значение указателя parent и вызывает callback_func для этого указателя с переданным ему экземпляром DataClass.

(Вы можете пропустить лямбду здесь и просто написать

 m_parentCallback = parent->callback_func;

, но лямбды более гибкие и, следовательно, «канонически» используются для этого. Плюс вы, вероятно, получите лучшие сообщения об ошибках, если parent не имеет callback_func.)

Чтобы использовать его, просто вызовите его как функцию:

wrapper::m_parentCallback(data);

https://godbolt.org/z/nUG9Bx

Вы, вероятно,в курсе, но я бы настоятельно не рекомендовал использовать глобальные переменные в такой тесной взаимосвязи. На данный момент (и, возможно, для «жизни» вашего проекта) он будет работать нормально, но это действительно не масштабируется. wrapper может быть сам по себе класс.

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