Как я могу передать функцию-член из производного класса в качестве обратного вызова? - PullRequest
0 голосов
/ 01 сентября 2018

у меня простой класс X

class X {
public:
    template<typename T>
    void doSomething(T &completion) {
        std::cout << completion(10) << std::endl;
    }
};

и класс A и B

class A {
public: 
 // some code
 X* c;
};

class B : public A {
public:
  int test(int x) {
    return x * x;
  }

  void execute() {
   auto lambda = [] (int x) { cout << x * 50 << endl; return x * 100; };
   c->doSomething(lambda); // works
   c->doSomething(&B::test); // does not work
  }
};

Я хочу передать методу doSomething метод-член класса B (или любой другой класс, производный от A), но он просто не работает: /

Ответы [ 3 ]

0 голосов
/ 01 сентября 2018

Вы имеете в виду c->doSomething([this](int x) { return this->test(x); });?

0 голосов
/ 01 сентября 2018

Сделайте B::test статическим методом, и он будет работать как написано:

static int test(int x) {
    return x * x;
}
// ...
c->doSomething(&B::test);

Это потому, что статический метод не требует неявного экземпляра (указатель this).

Если B::test должен быть обычным методом, то вы должны передать экземпляр с помощью лямбда-захвата, например:

c->doSomething([this] (int x) { return this->test(x); });

ПРИМЕЧАНИЕ: при получении этого кода для компиляции мне нужно было изменить ваше определение doSomething, чтобы оставить & вне T:

template<typename T>
void doSomething(T completion) {
    std::cout << completion(10) << std::endl;
}

Это предотвращает наложение l-value или неконстантного ограничения на тип указателя функции, что может помешать компилятору создавать временную лямбда-функцию.

0 голосов
/ 01 сентября 2018

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

Ваша проблема не имеет ничего общего с тем, что B является дочерним классом. Ваша проблема в том, что вы не связываете нестатическую функцию-член test() с ее экземпляром.

Вы можете легко решить эту проблему, либо , используя std::bind для возврата функтора :

c->doSomething(std::bind(&B::test, this, std::placeholders::_1));

и не забудьте #include <functional>,

или используйте лямбда , чтобы обернуть вызов, вставив this в лямбда захватов :

c->doSomething([this](int x){ return this->test(x); });

Примечание. Убедитесь, что параметр doSomething() был изменен на rvalue-ссылку , чтобы он мог должным образом принять все эти параметры обратного вызова как во временных объектах, так и в других случаях. Должно выглядеть так:

template<typename T>
void doSomething(T&& completion)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...