Как я могу получить доступ к члену объекта класса из его собственной функции обратного вызова? Я пытаюсь отправить объект вызывающего абонента в качестве параметра функции обратного вызова и получить к нему доступ из функции обратного вызова.
В следующем коде я получаю 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;
}
«Если я использую *this, я получаю упомянутую ошибку». Если вы используете *this
, это исправляет эту ошибку и просто отображает следующую ошибку. Удалите (test)
из test.onEvent(onUpdateEvent(test));
и сделайте параметры onUpdateEvent
и std::function
согласованными (либо по значению, либо по ссылке).
Примечание: я вполне ожидаю, что std::function<void(Test)>
— это не то, что вам нужно, скорее всего, вы хотите использовать функцию с переданным объектом, а не с его копией, поэтому вам понадобится std::function<void(Test&)>
— фактическая функция уже использует ссылку, так что вы также получите уже упомянутую @HolyBlackCat консистенцию.
Проблема в том, что вы используете возвращаемое значение вызова функции 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
, не обязательно — другие обратные вызовы могут изменить объект (и это разрешено намеренно) — поэтому правильность или нет зависит от варианта использования...
Ваше намерение — вызвать
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 да, параметры немного перепутаны, но... Что касается «самого простого» - это могло быть более импульсивно. Я часто выполняю обратные вызовы с функциями-членами (т. е. std::bind
и подобными шаблонами), возможно, мне захочется передать некоторые другие данные (старый добрый указатель void* userdata
из тех времен) или внести другие незначительные изменения — лямбды охватывают все эти случаи. Так что да, я должен признать, что просто передать указатель функции мне даже в голову не пришло, так как я не помню, когда в последний раз делал это...
Результат обратного вызова —
void
, вот в чем причина ошибки. Вы вызываете «обратный вызов» и передаете результат как параметр, что неверно.