Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Choosing a template instantiation at runtime though switch in C++

Tags:

c++

I have a set of functions that are templated both by an integer type Index and a class type T, that I "partially specialize" in the following manner:

// Integer type
enum Index{One,Two,Three,Four};

// Default implementation
template<int I>
struct Foo{
  template<typename T> static void bar(const T& x){ std::cout <<"default" << endl; }
};

// Template specializations
template<> 
struct Foo<One>{
  template<typename T> static void bar(const T& x){ std::cout << "one" << endl; }
};

This I use to select a particular index at the runtime of the program using a switch-statement (which should result in an efficient look-up table). The switch is independent of T:

template<typename T>
void barSwitch(int k, const T& x){
  switch(k){
    case ONE: Foo<ONE>::bar(x); break;
    case TWO: Foo<TWO>::bar(x); break;
    case THREE: Foo<THREE>::bar(x); break;
  }
}

This works fine, of course, but the class Foo is not the only class for which I would like to apply the switch. In fact, I have a lot of classes that are all templated by the same integer type. So I would like to "template" the class barSwitch above with the function "Foo" as well, so that I can plug in a different class or a different function. The only way I can think of to achieve this is to use a macro:

#define createBarSwitch(f,b) \
template<typename T> \
void barSwitch(int k, const T& x){ \
  switch(k){ \
    case ONE: f<ONE>::b(x); break; \
    case TWO: f<TWO>::b(x); break; \
    case THREE: f<THREE>::b(x); break; \
  }\
}

Is there some better, more C++ style way of doing this?

like image 747
Joel Avatar asked Feb 16 '12 22:02

Joel


People also ask

How do I force a template instantiation?

To instantiate a template function explicitly, follow the template keyword by a declaration (not definition) for the function, with the function identifier followed by the template arguments. template float twice<float>(float original); Template arguments may be omitted when the compiler can infer them.

Are templates instantiated at compile time?

Templates are instantiated in the process of converting each translated translation unit into an instantiation unit. A translation unit is essentially a source file. A translated translation unit (try to say that three times fast) is the output from compilation without templates instantiated.

How the instantiation of function template happens?

When a function template is first called for each type, the compiler creates an instantiation. Each instantiation is a version of the templated function specialized for the type. This instantiation will be called every time the function is used for the type.

What is instantiation of a template?

The act of creating a new definition of a function, class, or member of a class from a template declaration and one or more template arguments is called template instantiation. The definition created from a template instantiation to handle a specific set of template arguments is called a specialization.


1 Answers

Template template parameters are the key:

enum Index { One, Two, Three, Four };

template <template <Index> class Switcher, typename T>
void barSwitch(int k, const T & x)
{
    switch (k)
    {
        case 1: Switcher<One>::template bar<T>(x); break;
        case 2: Switcher<Two>::template bar<T>(x); break;
        default: assert(false);
    }
}

Usage:

template <Index I> struct Foo
{
    template <typename T> static void bar(const T & x);
};

barSwitch<Foo>(1, Blue);

(It is your responsibility to ensure that every possible template that you substitute for Switcher has a member template bar, of course. If not, you'll get a compile error.)

like image 114
Kerrek SB Avatar answered Nov 15 '22 03:11

Kerrek SB