Выполнение всех методов, на которые указывает пакет параметров шаблона

  1. Могу ли я создать пакет параметров шаблона указателей на методы (= функция-член)?
  2. Если да, то возможно ли создать (шаблонную) функцию, которая выполняет все методы в своем пакете параметров шаблона?

Упрощения:

  • Порядок выполнения указанных методов не имеет значения.
  • Все указатели методов имеют одинаковую сигнатуру (например, возвращают bool, имеют один и тот же базовый класс, не принимают аргументов)

person ManuelAtWork    schedule 20.07.2017    source источник
comment
Да, и да. Ты пробовал ? :)   -  person Quentin    schedule 20.07.2017
comment
@Quentin: Да, я так и сделал, но пока безуспешно. Не могли бы вы показать мне пример? Я еще не нашел пример в Интернете.   -  person ManuelAtWork    schedule 20.07.2017
comment
Можете ли вы показать одну из ваших попыток? Если вы не покажете свою попытку, мы не сможем показать, в чем ваша ошибка.   -  person max66    schedule 20.07.2017


Ответы (2)


template<class T, class...Ms>
void run_all(T* t, Ms&&... ms) {
  using discard=int[];
  (void)discard{0,(void(
    (t->*ms)()
  ),0)...};
}

Использовать:

struct foo {
  bool t1() { return true; }
  bool t2() const { return false; }
};
int main() {
  foo f;
  run_all(&f, &foo::t1, &foo::t2);
}

run_all тупой, но это потому, что у нас нет C++17.

template<class T, class...Ms>
void run_all(T* t, Ms&&... ms) {
  ((void)((t->*ms)()),...);
}

что немного проще, или даже:

template<class T, class...Ms>
void run_all(T* t, Ms&&... ms) {
  ((t->*ms)(),...);
}

который полагается на то, что t->*ms возвращает нормальный тип.

Мы также могли бы положиться на тот факт, что ms возвращает логическое значение и сделать:

template<class T, class...Ms>
void run_all(T* t, Ms&&... ms) {
  (void)std::initializer_list<bool>{(t->*ms)()...};
}

or

template<class T, class...Ms>
void run_all(T* t, Ms&&... ms) {
  using discard=bool[];
  (void)discard{false,(t->*ms)()...};
}

Обратите внимание, что все они выполняют свои методы по порядку и поддерживают передачу 0 методов.

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

Другие предназначены для обработки возможности того, что вызов возвращает тип, который перегружает operator,.

person Yakk - Adam Nevraumont    schedule 20.07.2017
comment
Большое спасибо за ваш ответ. Однако шаблоны не принимают пакеты параметров указателей на методы. - person ManuelAtWork; 21.07.2017
comment
@ManuelAtWork Я передаю указатели на методы. Таким образом, тип этих аргументов — это указатели на методы. Таким образом, они представляют собой пакеты параметров... указателей методов. Что именно вы подразумеваете под тем, что они не являются пакетами параметров указателей на методы? Вы имеете в виду, что другие типы могут быть приняты? Верно, но он будет скомпилирован только в том случае, если они переопределили ->*, и в таком случае какое вам дело? - person Yakk - Adam Nevraumont; 21.07.2017
comment
Все пакеты параметров вашего шаблона начинаются с class..., что означает тип пакетов параметров. Стандарт C++ также допускает нетиповые параметры шаблона, такие как целые числа или указатели. Вы передаете указатели методов, но не как параметры шаблона, а как параметры функции. Прошу прощения, если мой вопрос был двусмысленным. - person ManuelAtWork; 21.07.2017
comment
@ManuelAtWork О, это то, что ты имеешь в виду. Вот почему вы хотите опубликовать фактические попытки кода в вопросах; Я понятия не имел, что вы хотели передать их как нетиповые параметры шаблона. - person Yakk - Adam Nevraumont; 21.07.2017

class MyClass {

  /* The methods to be executed: */

  bool func_1() const { /* ... */ }
  bool func_2() const { /* ... */ }
  // ...


  /* The parameter pack expansion: */

  typedef bool (MyClass::*FuncPtr)() const;

  template<class T = void>
  void Expand() const {}  // Termination version.

  template<FuncPtr ptr, FuncPtr ... Args>
  void Expand() const {
    (this->*ptr)();
    Expand<Args...>();
  }


  /* The function that calls them all: */

  void RunAll() const {
    Expand< 
      &MyClass::func_1, // <-- input to parameter pack
      &MyClass::func_2
    >();
  }

};

Альтернативная версия без рекурсии:

class MyClass {

  /* The methods to be executed: */

  bool func_1() const { /* ... */ }
  bool func_2() const { /* ... */ }
  // ...


  /* The parameter pack expansion: */

  typedef bool (MyClass::*FuncPtr)() const;

  template<typename ... T> void ignore(T && ...) {}

  template<FuncPtr ... Args> 
  void Expand() const {
    ignore( ((this->*Args)(),0) ... );
  }

  /* The function that calls them all: */

  void RunAll() const {
    Expand< 
      &MyClass::func_1, // <-- input to parameter pack
      &MyClass::func_2
    >();
  }

};

(вклад @Yakk)

person ManuelAtWork    schedule 21.07.2017
comment
Украдите расширения пакета из моего ответа, чтобы избавиться от версии завершения без аргументов и удалить рекурсию. Первый, тот, что с disard, замените t на this и ms на ptrs и возьмите template<FuncPtr...ptrs> - person Yakk - Adam Nevraumont; 21.07.2017
comment
@Yakk Я так и сделал. Спасибо за безрекурсивный подход! - person ManuelAtWork; 24.07.2017
comment
Символы, начинающиеся с двойного подчеркивания, зарезервированы реализацией. Не имитируйте стандартный/системный стиль заголовочного файла; они разрешены и в некоторых случаях должны использовать этот стиль. - person Yakk - Adam Nevraumont; 24.07.2017
comment
@Yakk: я нашел еще более короткую версию, используя шаблон функции ignore. Он автоматически отключает предупреждения о неиспользуемых переменных. - person ManuelAtWork; 25.07.2017
comment
недостатком является то, что вы теряете гарантии заказа. Плюс в том, что вы можете удалить ,0 - person Yakk - Adam Nevraumont; 26.07.2017