Как отправить объект вызывающего абонента в качестве параметра функции обратного вызова

Как я могу получить доступ к члену объекта класса из его собственной функции обратного вызова? Я пытаюсь отправить объект вызывающего абонента в качестве параметра функции обратного вызова и получить к нему доступ из функции обратного вызова.

В следующем коде я получаю error: invalid use of void expression в этой строке test.onEvent(onUpdateEvent(test));

Одним из решений является определение тестового объекта как глобального, определение функции onEvent как void onEvent(const std::function<void()> &callback) и удаление параметров из функций обратного вызова.

Но мне хотелось бы знать, есть ли другой способ. Это пример кода:

#include <iostream>

#include <functional>

class Test
{
  public:
    int x;
    void onEvent(const std::function<void(Test)> &callback)
    {
            Test_Callback = callback;
    };

    std::function<void(Test)> Test_Callback;     

    void Update()
    {
        x += 1;
        if (Test_Callback)
        {
            Test_Callback(.......);  <--- What parameter to use? If i use *this, i get the error i mentioned
        }
    }
};

void onUpdateEvent(Test& t)
{
    printf("update %d\r\n", t.x);
}

int main()
{
    Test test;
    test.onEvent(onUpdateEvent(test));

    while (1)
    {
        test.Update();   
    }

    return 0;
}

Результат обратного вызова — void, вот в чем причина ошибки. Вы вызываете «обратный вызов» и передаете результат как параметр, что неверно.

Ulrich Eckhardt 10.04.2024 12:21

«Если я использую *this, я получаю упомянутую ошибку». Если вы используете *this, это исправляет эту ошибку и просто отображает следующую ошибку. Удалите (test) из test.onEvent(onUpdateEvent(test)); и сделайте параметры onUpdateEvent и std::function согласованными (либо по значению, либо по ссылке).

HolyBlackCat 10.04.2024 12:21

Примечание: я вполне ожидаю, что std::function<void(Test)> — это не то, что вам нужно, скорее всего, вы хотите использовать функцию с переданным объектом, а не с его копией, поэтому вам понадобится std::function<void(Test&)> — фактическая функция уже использует ссылку, так что вы также получите уже упомянутую @HolyBlackCat консистенцию.

Aconcagua 10.04.2024 12:37
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
3
58
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Проблема в том, что вы используете возвращаемое значение вызова функции onUpdateEvent(test) в качестве аргумента. Это неверно, поскольку onUpdateEvent имеет void в качестве возвращаемого типа.


Поэтому, чтобы решить эту проблему, не используйте возвращаемое значение вызова onUpdateEvent(test) в качестве аргумента. Вместо этого просто передайте указатель на onUpdateEvent в качестве аргумента, как показано ниже. Также обратите внимание на внесенные дополнительные изменения, которые выделены в комментариях к фрагменту кода:

class Test
{
  public:
    int x;
    void onEvent(const std::function<void(Test)> &callback)
    {
            Test_Callback = callback;
    };

//---------------------vvvvvvvvvvv------->same type as of onUpdateEvent's parameter
    std::function<void(const Test&)> Test_Callback;     

    void Update()
    {
        x += 1;
        if (Test_Callback)
        {
            Test_Callback(*this); // <--- What parameter to use? If i use *this, i get the error i mentioned
        }
    }
};
//-----------------vvvvv---------->added const here since this doesn't change anything
void onUpdateEvent(const Test& t)
{
    printf("update %d\r\n", t.x);
}

int main()
{
    Test test;
    //------------------------v--> pass pointer to function as argument instead of passing return value as arg
    test.onEvent(onUpdateEvent);

    while (1)
    {
        test.Update();   
    }

    return 0;
}

Рабочая демо

const-ность, безусловно, корректна для onUpdateEvent – и по-прежнему позволяет присваиваться неизмененному std::function объекту. Однако тот, у которого есть параметр const, не обязательно — другие обратные вызовы могут изменить объект (и это разрешено намеренно) — поэтому правильность или нет зависит от варианта использования...
Aconcagua 10.04.2024 12:43

Ваше намерение — вызвать

void onEvent(const std::function<void(Test)> &callback)

с обратным вызовом, но ваша линия

test.onEvent(onUpdateEvent(test));

фактически вызывает вашу функцию обратного вызова и пытается передать результат.

Самый простой/самый общий способ исправить это — использовать лямбду:

test.onEvent([](Test myTest) { onUpdateEvent(myTest); });

Примечание. Я не совсем уверен, какой «тест» вы хотите пройти, поэтому я предполагаю, что вы хотите использовать параметр «test» в функции обратного вызова, а не использовать тест из вызова onEvent...

Я бы предпочел предположить, что std::function также должен принять свой параметр по ссылке (это не является ошибкой) – и если это так, то «самым простым» на самом деле было бы просто передать функцию: test.onEvent(&onUpdateEvent);...

Aconcagua 10.04.2024 12:49

@Aconcagua да, параметры немного перепутаны, но... Что касается «самого простого» - это могло быть более импульсивно. Я часто выполняю обратные вызовы с функциями-членами (т. е. std::bind и подобными шаблонами), возможно, мне захочется передать некоторые другие данные (старый добрый указатель void* userdata из тех времен) или внести другие незначительные изменения — лямбды охватывают все эти случаи. Так что да, я должен признать, что просто передать указатель функции мне даже в голову не пришло, так как я не помню, когда в последний раз делал это...

Christian Stieber 10.04.2024 13:12

Другие вопросы по теме