#c
#c
Вопрос:
У меня есть рабочий класс, который принимает инициализацию указателя функции обратного вызова в конструкторе. Я хотел бы создать экземпляр worker в своем классе и предоставить указатель на функцию-член в качестве обратного вызова.
Рабочий класс:
class Worker
{
public:
typedef int (*callFunct)(int);
Worker(callFunct callback = nullptr);
~Worker();
private:
callFunct m_callback = nullptr;
};
Worker::Worker(callFunct callback) : m_callback(callback)
{
}
и вот мой класс, в котором я хотел бы иметь Worker
экземпляр и функцию обратного вызова члена:
class myClass
{
public:
myClass();
~myClass() = default;
private:
int myCallback(int x);
Worker m_worker {amp;myClass::myCallback};
};
К сожалению, это не компилируется:
error: could not convert '{amp;myClass::myCallback}' from '<brace-enclosed initializer list>' to 'Worker'
Я знаю, что при работе с указателем на класс-член я также должен предоставить объект экземпляра. Но как правильно поступить в этой ситуации, когда мне нужно иметь указатель на член класса?
Комментарии:
1. добавить
static
вint myCallback(int x);
. Этот вопрос страдает от проблемы XY , поэтому не может дать лучшего ответа.2. Как сказал @MarekR, добавление
static
работает: godbolt.org/z/hrb3WjeKr3. Кстати, вы можете использовать godbolt.org для проверки с использованием разных компиляторов я обнаружил, что clang в данном случае дает немного лучшее описание ошибки, чем gcc.
Ответ №1:
Указатели на функции, не являющиеся членами, — это не то же самое, что указатели на (нестатические) функции-члены!
Разница в том, что (нестатической) функции-члену требуется объект для вызова, который не имеет указателей на функцию, не являющуюся членом.
Для создания обратного вызова можно использовать std::function
лямбды и:
class Worker
{
public:
using callFunct = std::function<int(int)>;
Worker(callFunct callback)
: m_callback(callback)
{
}
private:
callFunct m_callback;
};
class myClass
{
public:
myClass()
: m_worker([this](int x) { return myCallback(x); })
{
}
private:
int myCallback(int x);
Worker m_worker;
};
Или, если для обратного вызова не требуется доступ к myClass
объекту, создайте функцию static
:
class myClass
{
public:
myClass();
private:
static int myCallback(int x);
Worker m_worker {amp;myClass::myCallback};
};
[Как упоминалось другими в комментариях к вопросу]
Или простой лямбда, который делает то, что myClass::myCallback
будет делать.
Комментарии:
1. Как реорганизовать ваш пример, чтобы не использовать std::function? Я бы хотел не менять
Worker
класс и сохранитьtypedef int (*callFunct)(int);
И, во-вторых, что вы имеете в видуOr a plain lambda that does what myClass::myCallback would do.
?2. @SebastianGreen Если вы хотите использовать указатели на функции, не являющиеся членами, то вам нужно использовать либо
static
функцию-член, либо функции, не являющиеся членами (конечно), либо не захватывающие лямбды. Вы не можете использовать простые функции-члены без другой работы (например, используя дополнительные аргументы указателя «пользовательские данные», где статическая функция-член может использовать указатель «пользовательские данные» в качестве указателя на объект, а затем вызывать фактическую функцию-член).3.
static
Конечно, член не является опцией, поскольку он не может получить доступ к нестатическим членам из класса, равно как и к функциям, не являющимся членами. Можете ли вы привести пример, как это сделать с помощью лямбда-выражения без захвата? Можем ли мы сохранитьtypedef int (*callFunct)(int);
определение изWorker
класса? Можем ли мы избежатьstd::function
этого, заменив его, скажем, на `std::bind’? Спасибо.4. @SebastianGreen Статическая функция может работать, если у вас есть какой-то способ передать на нее указатель «пользовательские данные». Этот указатель может быть указателем на объект, и тогда статическая функция может вызвать правильную функцию, используя объект. Однако лямбда-выражение без захвата будет невозможно, поскольку вам все равно нужно захватить объект. Я упомянул об этом только потому, что они могут быть неявно преобразованы в указатель на функцию, не являющуюся членом.