5

I have a class which returns the specific device based on runtime.

struct ComponentDc;
struct ComponentIc;

typedef Device<ComponentDc> DevComponentDc;
typedef Device<ComponentIc> DevComponentIc;

template<class Component>
class Device{
 Device<Component>* getDevice() { return this; }
 void exec() { }
};

In exec(), I'd like to print "Hello" if the component type is ComponentDc and world if it is ComponentIc. Also, these are the only two types with which Device can be created.

How do I do this ?

brainydexter
  • 19,826
  • 28
  • 77
  • 115

4 Answers4

4

You have two classic possibilities.

First, use two global function overloads, one for ComponentDc, one for ComponentIc:

void globalExec(ComponentDc) { std::cout << "Hello"; }
void globalExec(ComponentIc) { std::cout << "World"; }

void Device<Component>::exec() { globalExec(Component); }

Second, use traits-class: pure template class with no fields and with different typedefs and only static functions as methods. This class has own specializations for different possible argument types.

template<Component> class DeviceTraits {};

template<> class DeviceTraits<ComponentDc> { 
    static std::string getMessage() { return "Hello"; }
};

template<> class DeviceTraits<ComponentIc> { 
    static std::string getMessage() { return "World"; }
};

void Device<Component>::exec() { 
    std::cout << DeviceTraits<Component>::getMessage(); 
}

The advantage of using traits classes is that you don't have to spoil your global namespace with several functions.

About partially specializing the Device class itself - it is not always possible, and it is considered more convenient to move any template-argument-specific code into traits class.

This is the classic approach used in STL. Alternatively, you can use boost::enable_if or std::enable_if (for the latest compilers).

Mikhail
  • 20,685
  • 7
  • 70
  • 146
  • I'm afraid global functions is not an option. I simplified my question here, so it has to be a member. Can you elaborate on traits classes ? Thanks – brainydexter Mar 19 '13 at 08:31
3

You could instantiate template explicitly:

template<> class Device<ComponentDc> {
    ...
    void exec() { cout << "Hello"; }
};

The same goes for Device<ComponentIc>.

Also, if you want to restrict template parameters to a specific set, you should think of inheritance or composition instead of templates.

umi
  • 3,782
  • 2
  • 15
  • 12
1

You can also use boost::enable_if

http://www.boost.org/doc/libs/1_53_0/libs/utility/enable_if.html http://www.boost.org/doc/libs/1_44_0/libs/type_traits/doc/html/boost_typetraits/reference/is_same.html

void Device<Component>::exec(boost::enable_if< boost::is_same<Component,ComponentDc> >* enabler = 0)
{
}

void Device<Component>::exec(boost::enable_if< boost::is_same<Component,ComponentIc> >* enabler = 0)
{
}
sylvain.joyeux
  • 1,659
  • 11
  • 14
0

Use for instance template specialization: http://www.cprogramming.com/tutorial/template_specialization.html

Here to use it for the specific method: Template specialization of a single method from a templated class

Community
  • 1
  • 1
uberwach
  • 1,119
  • 7
  • 14