10

Is it possible to specialize a class method for individual enum values? Specifically I have an enum and a class as follows:

#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;
         }
      }
};

I want to specialize getSound function for each of the enum values to get rid of the switch case. Is such template specialization possible?

Vimal
  • 436
  • 1
  • 4
  • 14

2 Answers2

21

Yes, it is possible. Look at the sample below.

#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>();
}
273K
  • 29,503
  • 10
  • 41
  • 64
5

I don't see why you want to go for specialization. If this example is indicative and your enumnerators are sequential and starting from 0, you can just use a lookup table:

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));
}

And that's it. It also replaces the the "unknown" string by an exception being thrown. I feel this is warranted, since a scoped enumeration implies we expect strict checking of the value being passed. And breaking that is an exceptional situation.


Even your edited question can be subjected to a lookup table:

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
}
StoryTeller - Unslander Monica
  • 165,132
  • 21
  • 377
  • 458
  • Thanks for your reply. This was only an indicative example. There is a bunch of processing happening inside the case. That is why we want to use specialization. I have edited the question to reflect this. – Vimal Dec 06 '17 at 06:29
  • @vchandra - That still doesn't disqualify a lookup table. Hang on a sec – StoryTeller - Unslander Monica Dec 06 '17 at 06:32
  • Sorry for my late reply. And thanks a lot for taking the time to provide me with different solutions. I learnt quite a few things from this answer. I am accepting answer by S.M. as its closer to my original question around template specialization. Thanks again. – Vimal Dec 06 '17 at 13:40