Передача указателя на метод generi c в шаблонный класс - PullRequest
0 голосов
/ 22 апреля 2020

Я хочу создать шаблонный класс, конструктор которого принимает указатель на объект и указатель на один из методов объекта. Класс шаблона должен принимать метод с любыми аргументами, поэтому я подумал, что тип метода должен быть параметром шаблона. Я также предпочел бы принять метод с любым типом возвращаемого значения, но было бы нормально ограничить его возвращением void. Код ниже не компилируется. Какой правильный синтаксис?

template <typename Obj, typename Method>
class Foo
{
public:
  Foo(Obj *obj, Obj::*Method method)
    :mObj(obj), mMethod(method)
  {}

  void callMethod()
  {
    mObj->mMethod();
  }

private:
  Obj* mObj;
  Obj::*Method mMethod;
};

class Bar
{
public:
  // I want it to work no matter what arguments this method takes.
  void method() {}
};

Bar bar;
Foo <Bar, void(Bar::*)()> foo(&bar, &Bar::method);

Я получаю эту ошибку в конструкторе Foo:

error C2059: syntax error: '<tag>::*'

Мой предыдущий вопрос по этой теме c был помечен как дубликаты, но в приведенных примерах указан точный тип метода, который можно передать, и мне нужно, чтобы он был обобщенным c.

1 Ответ

2 голосов
/ 22 апреля 2020

Для начала у вас есть пара проблем syntacti c в вашем коде. Кроме того, вам не нужно Method, чтобы вообще быть аргументом шаблона, поскольку вы всегда хотите передать функцию-член типа Object.

Чтобы получить переменное число аргументов в callMethod, просто предоставьте пакет параметров c variadi для Foo. Кроме того, вы можете определить тип возврата функции callMethod.

Собрав все это вместе, вы можете получить:

template <typename Obj, typename Ret, typename ...Args>
class Foo
{
public:
  Foo(Obj *obj, Ret (Obj::*method)(Args...))
    : mObj(obj), mMethod(method)
  {}

  Ret callMethod(Args... args)
  {
    return (mObj->*mMethod)(args...);
  }

private:
  Obj* mObj;
  Ret (Obj::*mMethod)(Args...);  // this is essentially 'Method'
};

Теперь, если у вас есть классы с переменным числом аргументов для Для конкретной функции она работает нормально:

class Bar
{
public:
  void method() { std::cout << "bar"; }
};

class Car
{
public:
  int method2(int, double) { 
    std::cout << "car"; 
    return 42;
   }
};

int main()
{
Bar bar;
Car car;
Foo a (&bar, &Bar::method);
Foo b (&car, &Car::method2);
a.callMethod();  // prints 'bar'
b.callMethod(5, 3.2);  // prints 'car'
}

Вот рабочая демоверсия .

Обратите внимание, что в реальном решении вы, вероятно, захотите совершить пересылку аргументов , но это должно привести вас на правильный путь.

Кроме того, до c ++ 17 нет CTAD (вычитание аргумента шаблона класса), поэтому вы должны указать аргументы шаблона при построении Foo объекты, как это:

Foo <Bar, void> a(&bar, &Bar::method);
Foo <Car, int, int, double> b(&car, &Car::method2);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...