Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Template specialization for enum values

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?

like image 869
chandra.v Avatar asked Dec 06 '17 04:12

chandra.v


2 Answers

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>();
}
like image 90
273K Avatar answered Nov 15 '22 21:11

273K


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
}
like image 21
StoryTeller - Unslander Monica Avatar answered Nov 15 '22 21:11

StoryTeller - Unslander Monica