mardi 18 octobre 2011

C++: switch on any data type (part 2)

(See part 1 of this post here.)

In this second version, the idea is to have the same function called on triggering, but with a different argument value for each case.

The class will be very similar to first version. The difference is that here, instead of storing the function in the map, we store the argument value. i.e. instead of having
std::map<KEY, FUNC>, we change to  std::map<KEY, ARG>.

Here is the full class. Don't forget to add the needed headers. And as usual with templated classes, this takes place in a header file.


template < typename KEY, typename FUNC, typename ARG > class SWITCH2
{
   public:
      SWITCH2()
      {
          myFunc = 0;
      }

      void Process( const KEY& key )
      {
         assert( myFunc ); // needed !
         typename std::map<KEY,ARG>::const_iterator it = myMap.find( key );
         if( it != myMap.end() )    // If key exists, call function
            myFunc( it->second );  // with correct argument
         else                       // else, call function with
            myFunc( DefArg );      // default argument
      }

      void AddArgument( const KEY key, ARG value )
      {
         myMap[ key ] = value;
      }
      void SetFunction( FUNC f )
      {
         myFunc = f;
      }
      void SetDefault( ARG def )
      {
         DefArg = def;
      }

   private:
      std::map< KEY, ARG > myMap;
      FUNC myFunc; // the function
      ARG  DefArg; // default value, the type needs
                   //   a default constructor
};

I removed here the uniqueness test, as it seemed less relevant in this situation. But you can write it back if needed.
Also note the 'assert()' checking, to make sure we don't call a function that hasn't been defined. You can easily replace this by some custom error handling function instead (exception, or whatever.)


And again, remember that this trick can only be used in specific cases where either you have to call different functions with the same argument, or the same function with different argument values.

Other solutions to this problem can be found (besides switching to another programming language, I mean...), you could also use function pointers, although this is less natural in C++.