Указатель функции C на функцию-член

#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/hrb3WjeKr

3. Кстати, вы можете использовать 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 Статическая функция может работать, если у вас есть какой-то способ передать на нее указатель «пользовательские данные». Этот указатель может быть указателем на объект, и тогда статическая функция может вызвать правильную функцию, используя объект. Однако лямбда-выражение без захвата будет невозможно, поскольку вам все равно нужно захватить объект. Я упомянул об этом только потому, что они могут быть неявно преобразованы в указатель на функцию, не являющуюся членом.