Специализация шаблона для перечислимых значений

Можно ли специализировать метод класса для отдельных значений перечисления? В частности, у меня есть перечисление и класс следующим образом:

#include <iostream>
#include <stdio.h>

using namespace std;

enum class Animal { dog, cat, bird  };
class Sound
{
   public:
      static void getSound ( const Animal& arg )
      {
         switch ( arg )
         {
           case Animal::dog:
             // dog specific processing
             break;

           case Animal::cat:
             // cat specific processing
             break;

           case Animal::bird:
             // bird specific processing
             break;

           default:
             return;
         }
      }
};

Я хочу специализировать функцию getSound для каждого из значений перечисления, чтобы избавиться от регистра переключателя. Возможна ли такая специализация шаблона?

2 ответа

Решение

Да, это возможно. Посмотрите на образец ниже.

#include <iostream>
#include <stdio.h>

using namespace std;

enum class Animal { dog, cat, bird  };
class Sound
{
   public:
      template<Animal animal>
      static void getSound ();
};

template<>
void Sound::getSound<Animal::dog> ()
{
    // dog specific processing
}

template<>
void Sound::getSound<Animal::cat> ()
{
    // cat specific processing
}

template<>
void Sound::getSound<Animal::bird> ()
{
    // bird specific processing
}

int main()
{
    Sound::getSound<Animal::dog>();
}

Я не понимаю, почему вы хотите пойти на специализацию. Если этот пример показателен и ваши перечислители являются последовательными и начинаются с 0, вы можете просто использовать справочную таблицу:

enum class Animal { dog, cat, bird, count = (bird - dog + 1) };

static std::string getSound ( Animal arg ) // Pass an enumeration by value, it's cheaper
{
  std::array<char const *, static_cast<std::size_t>(Animal::count)> const sound {{
    "bark", "meow", "chirp"
  }};
  return sound.at(static_cast<std::size_t>(arg));
}

И это все. Это также заменяет "unknown" Строка по исключению бросается. Я чувствую, что это оправдано, так как перечисление в рамках определенной области подразумевает, что мы ожидаем строгой проверки передаваемого значения. И ломать это исключительная ситуация.


Даже ваш отредактированный вопрос может быть подвергнут поисковой таблице:

static void getSound ( Animal arg ) // Pass an enumeration by value, it's cheaper
{
  std::array<std::function<void(void)>,
            static_cast<std::size_t>(Animal::count)> const handler{{
    [] { /*Process for dog*/ },
    [] { /*Process for cat*/ },
    [] { /*Process for bird*/ }
  }};
  handler.at(static_cast<std::size_t>(arg))(); // The last () is invocation
}
Другие вопросы по тегам