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?
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.
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.
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.
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.
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.)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With