Search code examples
c++templatesmacrosmetaprogramming

C++ variable as a template parameter


Is it possible to use variable as template parameter without switch or if else statements for each possible value?

enum A {a, b, c, d};
template<A> void f() {/* default */};
template<> void f<A::a>() {/* ... */}
template<> void f<A::b>() {/* ... */}
template<> void f<A::c>() {/* ... */}

void execute(A action) {
   f<action>()
}

I could use switch statement.

void execute(A action) {
    switch (action) {
        case A::a:
            f<A::a>();
            break;
        case A::b:
            f<A::b>();
            break;
        case A::c:
            f<A::c>();
            break;
    }
}

Or I could add function pointers to a map and use this map afterwards.

std::map<A, void(*)()> mp = {
    {A::a, f<A::a>},
    {A::b, f<A::b>},
    {A::c, f<A::c>}
};

void execute(A action) {
    mp[action]()
}

But both of these solutions require me to specify the mapping manually.

Is there a way of calling function based on a variable? Maybe using macro with function definition, or using template metaprogramming.


Solution

  • You can sort-of do what you want, but it only works if the value of action is known at compile-time. i.e.:

    #include <stdio.h>
    
    enum A {a, b, c, d};
    
    template<A> void f() {}
    template<> void f<A::a>() {printf("f<A::a>() called\n");}
    template<> void f<A::b>() {printf("f<A::b>() called\n");}
    template<> void f<A::c>() {printf("f<A::c>() called\n");}
    
    template<A action> void execute() {
       f<action>();
    }
    
    int main(int, char**)
    {
       constexpr A actionA = A::a;
       constexpr A actionB = A::b;
       constexpr A actionC = A::c;
    
       execute<actionA>();
       execute<actionB>();
       execute<actionC>();
    
       return 0;
    }
    

    .... yields this output:

    $ g++ temp.cpp -std=c++11
    $ ./a.out 
    f<A::a>() called
    f<A::b>() called
    f<A::c>() called
    

    If you don't/can't know what value action is supposed to have during compilation, then templates are not the right tool for the job, because all the "which-templated-function-should-be-called-here" decisions are made at compile-time.