How do I force the compiler to evaluate a switch at compile time?

Viewed 248

I'm working on an embedded project (only C++14 compiler available) and I would like to optimize the speed of execution.

Here is an example of what I am doing.

enum gpio_type{
  TYPE_1,
  TYPE_2
}

template <gpio_type T>
class test{
  test(){}

  void set_gpio(bool output)
  {
    switch (T)
    {
      case TYPE_1:
        do_something();
        break;

      case TYPE_2:
        do_something_else();
        break;
    }
  }
}

Will the compiler automatically remove the dead code at compile time? If it does, it is a standard feature or compiler dependent? If it does not, is it possible to write the code in a way that will force optimizing?

4 Answers

You could specialize set_gpio for the different enum values - eg. :

template <gpio_type T>
class test{
  public:
    test(){}

    void set_gpio(bool output);
};

template<> void test<TYPE_1>::set_gpio(bool output) {
  do_something();
}

template<> void test<TYPE_2>::set_gpio(bool output) {
  do_something_else();
}

As other answers have indicated, you might not need to if your compiler is anywhere close to decent at optimizing. But the above might be more readable nevertheless.

Constant propagation and dead code elimination are one of the simplest compiler optimizations. And since T is a compile time constant I would be extremely extremely surprised if the code isn't optimized by any compiler.

I have tested 15 compilers and platforms on godbolt from the venerable x86 to arm, avr, risc-v, raspberry and arduino (and more). All of them just compile to the equivalent of a tail call jump. No tests, no conditional jumps. Go check it out for yourself.

At this point I can say with reasonable confidence that there is no performance reason to modify your code.

That might depend on if you turn on optimization or not and how intelligent your compiler is. I guess current compilers would optimize in this case at least if they inline the function.

But if you want to be 100% sure

  • specialize the template for different enum values or
  • use your switch and look at the assembler output of your compiler to check if the compiler optimized like you want it or
  • use C++17 and if constexpr

I would pass the functor (do_something or do_something_else) as a template argument.

Thus, your code of set_gpio becomes clearer and you are sure to have a compile time deduction which function to take.

In this post you can see how this is done: Function passed as template argument

Related