C ++ 11: правильно развернуть пакет параметров шаблона в завершающем возвращаемом типе - PullRequest
0 голосов
/ 26 мая 2020

Я пытаюсь преобразовать константу времени выполнения в константу времени компиляции в моей программе на C ++ 11, используя оператор switch. У меня enum SomeEnum {A, B, C};, и в зависимости от его значения я хочу вызвать функцию-шаблон f<A>(), f<B>() или f<C>(). В моем коде много шаблонных функций, которые зависят от SomeEnum (а также от других параметров шаблона), поэтому я решил сделать специальную функцию dispatch. Вот код, который я пытаюсь скомпилировать:

#include <utility>

enum SomeEnum {
      A, B, C
};

template<template<SomeEnum, typename...> class FUNCTOR, typename ...OTHERS, typename ...ARGS> inline auto dispatch (
    SomeEnum const type,
    ARGS&&... args
) -> decltype( FUNCTOR<A, OTHERS...>::function(std::forward<ARGS>(args)...) ) { //Problem here
    switch(type) {
        case A:
            return FUNCTOR<A, OTHERS...>::function(std::forward<ARGS>(args)...);
        case B:
            return FUNCTOR<B, OTHERS...>::function(std::forward<ARGS>(args)...);
        case C:
            return FUNCTOR<C, OTHERS...>::function(std::forward<ARGS>(args)...);
        default:
            //Do not call any function if enum value is wrong, just return something:
            return decltype( FUNCTOR<A, OTHERS...>::function(std::forward<ARGS>(args)...) )();
    }
}

template<SomeEnum T> struct TemplateFunctor1 {
    static inline int function(int) { return 0; }
};

template<SomeEnum T, class OTHER> struct TemplateFunctor2 {
    static inline int function(int) { return 0; }
};

int main(void) {
    dispatch<TemplateFunctor1>(B, 0); //Problem here!

    dispatch<TemplateFunctor2, int>(B, 0);

    return 0;
}

(мне не нужно обрабатывать случай, когда тип возвращаемого значения функции зависит от параметра шаблона)

Я получаю сообщение об ошибке при компиляции строка dispatch<TemplateFunctor1>(B, 0);, где только один параметр шаблона, требуемый TemplateFunctor1. Сообщения об ошибках следующие:

error: no matching function for call to 'dispatch(SomeEnum, int)'

note: candidate: template<template<SomeEnum <anonymous>, class ...> class FUNCTOR, class ... OTHERS, class ... ARGS> decltype (FUNCTOR<(SomeEnum)0u, OTHERS ...>::function((forward<ARGS>)(dispatch::args)...)) dispatch(SomeEnum, ARGS&& ...)

note: template argument deduction/substitution failed

error: wrong number of template arguments (2, should be 1) в этой части кода: FUNCTOR<A, OTHERS...> конечного возвращаемого типа.

Итак, я попытался изменить FUNCTOR<A, OTHERS...> в конечном возвращаемом типе на FUNCTOR<A>, тогда строка dispatch<TemplateFunctor2, int>(B, 0); не может быть скомпилирована. В нем говорится, что я указал неправильное количество параметров шаблона (1, должно быть 2), что является вполне ожидаемой ошибкой.

Я не понимаю, почему та же конструкция decltype() работает в default переключить ветвь, но не работает в завершающем возвращаемом типе?

Я могу исправить свой код, изменив стандарт на C ++ 14 и полностью удалив конечный возвращаемый тип, но тогда я не пойму, что происходит здесь.

Я также пробовал разные компиляторы (I CC, G CC, Clang), и все они выдают похожие сообщения об ошибках, поэтому здесь не может быть ошибки компилятора.

1 Ответ

0 голосов
/ 27 мая 2020

Я не знаю, в чем проблема, но, похоже, этот обходной путь работает:

  template <template<SomeEnum, typename...> class FUNCTOR, typename... X>
  struct Wrapper
  {
      using Type = FUNCTOR<A, X...>;
  };

  template<template<SomeEnum, typename...> class FUNCTOR, typename ...OTHERS, typename ...ARGS> 
  inline auto dispatch (
      SomeEnum const type,
      ARGS&&... args
  ) -> decltype( Wrapper<FUNCTOR, OTHERS...>::Type::function(std::forward<ARGS>(args)...) ) { //No problem here
...