0

Here is a simple example (the idea is to avoid a huge if..else or switch block inside a function):

namespace foo {
   enum class VALUES : int { val_0 = 0, val_1 = 1 };

   template<VALUES T>
   void print();

   template<>
   void print<VALUES::val_0>() { std::cout << "val_0\n"; }

   template<>
   void print<VALUES::val_1>() { std::cout << "val_1\n"; }

   void bar(int type) {
      VALUES v = static_cast<VALUES>(type);
      print<v>(); //error C2971 - "v" is a non-constant argument at compile-time
   }
};

The question is how to call print<...>() based on the bar's parameter? Please do not suggest to use if..else or switch.

Dmitrii
  • 98
  • 6
  • 3
    Template arguments must be known at compile time. If the argument isn't known at compile time - you can't use it as a template argument. – Algirdas Preidžius Jan 29 '21 at 10:06
  • 2
    If templates are out, and you shudder to even think about `if`/`else` or `switch`, last option would be to use `std::(unordered_)map`, but `switch` is generally superior over map. – Yksisarvinen Jan 29 '21 at 10:11
  • 1
    What's wrong with using `if`/`else` or a good old `switch`? – Lukas-T Jan 29 '21 at 10:16
  • @churill I want to speed up some functionality. `if/else` spends some time to choose a branch – Dmitrii Jan 29 '21 at 10:52
  • 2
    @Dmitrii So how, if it was possible, would the runtime decide which template specialization to call? Magic? It would also need to choose a branch, no? – Lukas-T Jan 29 '21 at 10:55
  • @churill I was thinking about template metaprogramming but at the moment have a solution also with multiple `if/else` and it uses static functions which I also want to avoid due to some specifics, moreover the solution is even slower – Dmitrii Jan 29 '21 at 13:12
  • But templates don't exist at runtime. Templates are just a mechanism to generate a family of functions (or classes, etc.) . If it's just about printing the enum a simple `switch` should be the fastest. Templates are the wrong approach here. – Lukas-T Jan 29 '21 at 13:18

2 Answers2

0

Templates are deduced at compile time. Which means that those template arguments are constant (at compile time). In your case, int type is not a constant type and so is VALUES v. In order to resolve v at compile time, you need to mark is as constexpr VALUES v; and which also means that you need to initialize it with values. In this case, with compile time resolvable values. That's why this works,

constexpr VALUES v = VALUES::val_0;
print<v>(); 

But not this,

VALUES m = VALUES::val_0;
constexpr VALUES v = m;    // As soon as you do this, it is no longer resolvable at compile time.
print<v>(); 

So the simplest answer is, you will have to use if/else, switch or templates to get it done.

D-RAJ
  • 3,263
  • 2
  • 6
  • 24
0

Here is a way to do so: https://stackoverflow.com/a/66171400/15104979 we just need a storage for all those functions and also they can be not templated. Also for non-members the Callback can be defined like using Callback = void(*)();. But we have to measure both cases: with if/else and Callback, specifically for your case.

Dmitrii
  • 98
  • 6