Как удалить некоторые функции в спецификации шаблона для типа void в C ?

#c #templates

Вопрос:

У меня есть занятие TriggerEvent :

 template <typename ReturnType, typename... ArgumentTypes>
class TriggerEvent<ReturnType(ArgumentTypes...)>
{
 public:
  using EventCallback = std::function<ReturnType(ArgumentTypes...)>;
  using InvokeCallback = std::function<bool(const ReturnTypeamp;)>;

  void Subscribe(EventCallbackamp;amp; callback);
  void Clear();

  void Invoke(ArgumentTypesamp;amp;... args);
  void Invoke(ArgumentTypesamp;amp;... args, InvokeCallbackamp;amp; invoke_callback);

 private:
  std::mutex access_mtx_;
  std::list<EventCallback> event_callbacks_;
};
 

Я не могу скомпилировать объект этого класса с шаблоном TriggerEvent<void(T) >, потому void что тип > не может использоваться для InvokeCallback псевдонима и в Invoke методе с обратным вызовом в его реализации.
Псевдоним и метод для ReturnType этого отличаются от void . Как я могу удалить псевдоним и метод из класса, когда ReturnType он есть void ?

Комментарии:

1. Специализация по данному void делу?

2. Дело не только в том, чтобы удалить псевдоним. Вам также необходимо убедиться, что остальная часть кода действительно работает. Какой метод лучше всего, будет зависеть от остальной части вашего кода. Специализации SFINAE и шаблонов-это два ваших основных варианта.

3. @Someprogrammerdude, вы имеете в виду создание триггерного события второго класса со специализацией void? Я знаю об этом, но я пытаюсь найти эффективный способ, потому что в этом случае мне нужно скопировать и вставить много кода.

Ответ №1:

Вы можете использовать вспомогательный шаблон для создания соответствующего типа обратного вызова invoke:

  • bool(T)
  • bool() когда T == void

Вот так:

 template <typename ReturnType>
struct invoke_callback_ref {
  using type = bool(const ReturnTypeamp;);
};

template <>
struct invoke_callback_ref<void> {
  using type = bool();
};

template <typename ReturnType, typename... ArgumentTypes>
class TriggerEvent {
public:
  using EventCallback = std::function<ReturnType(ArgumentTypes...)>;
  using InvokeCallback = std::function<typename invoke_callback_ref<ReturnType>::type>;
  . . .
 

Однако помните, что std::function это связано с накладными расходами во время выполнения.

Я бы использовал std::function только тогда, когда это неизбежно — например, при хранении обратных вызовов событий в списке. Во всех других местах используйте вызываемый тип напрямую. Это устраняет проблему работы со ссылками на void , и вы можете просто использовать if constexpr их для вызова void обратного вызова.

Например:

 template <typename ReturnType, typename... ArgumentTypes>
class TriggerEvent {
public:
  using EventCallback = std::function<ReturnType(ArgumentTypes...)>;

  template<typename T>
  void Subscribe(Tamp;amp; callback) {
    event_callbacks_.emplace_back(std::forward<T>(callback));
  }

  void Invoke(ArgumentTypesamp;amp;... args) {
    for (autoamp; cb : event_callbacks_) cb(args...);
  }

  template<typename T>
  void Invoke(ArgumentTypesamp;amp;... args, Tamp;amp; invoke_callback) {
    for (autoamp; cb : event_callbacks_) {
      if constexpr (std::is_same_v<ReturnType, void>) {
        cb(args...);
        invoke_callback();
      } else {
        invoke_callback(cb(args...));
      }
    }
  }

private:
  std::list<EventCallback> event_callbacks_;
};
 

Живая демонстрация