0

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.

Tellegar
  • 81
  • 7
  • 8
    Template arguments must be compile-time constants. `action` is not. It's not clear why you even want `f` to be a template; it looks like you just want a regular function to which you can pass `A action` as a parameter. – Igor Tandetnik Jan 02 '23 at 05:09
  • Does this answer your question? [Passing a variable as a template argument](https://stackoverflow.com/questions/11081573/passing-a-variable-as-a-template-argument) – Raymond Chen Jan 02 '23 at 07:29
  • To "convert" runtime value to compile time value, a switch or a table is required... – Jarod42 Jan 02 '23 at 08:36
  • static for loop can solve my question https://stackoverflow.com/questions/42005229/why-for-loop-isnt-a-compile-time-expression-and-extended-constexpr-allows-for-l – Tellegar Jan 15 '23 at 02:31

1 Answers1

0

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.

Jeremy Friesner
  • 70,199
  • 15
  • 131
  • 234
  • I don't know the value at compile time, that is the problem. I want to call a corresponding function based on a variable. – Tellegar Jan 02 '23 at 08:54
  • 3
    @Tellegar So what you want is *runtime* polymorphism. But templates are *compile-time* polymorphism. – Konrad Rudolph Jan 02 '23 at 08:58
  • @KonradRudolph I still need the mapping between values and objects/functions. So the question really is whether it is possible to create this mapping together with the function definitions. – Tellegar Jan 02 '23 at 09:13
  • 1
    @Tellegar Right, and the answer to that question is: yes, by using runtime polymorphism. Like e.g. your `switch` code. There's no way of getting around encoding this mapping manually in *some* way. – Konrad Rudolph Jan 02 '23 at 09:14
  • 2
    Virtual methods might be the way to go here. – Jeremy Friesner Jan 02 '23 at 19:49