1

Do we have a switch constexpr support in C++?

For context, we all know that we have if constexpr for compile-time if statements. Those if-statements will have very low overhead as compiler will evaluate them at compile time. We (or in particular I) use them when we do template specializations.

I was wondering if we have the same thing for switch or not. I am interested in using a switch statement instead of long if constexpr list with the same run-time overhead.

Example:

Considering this code:

template <int OP>
int mul(int in) {
  if constexpr (OP == 1) {
    return in * 2;
  } else if constexpr (OP == 2) {
    return in * 3;
  } else {
    return in * 4;
  }
}

Is the following code equivalent to the above code, compilation-wise?

template <int OP>
int mul(int in) {
  switch(OP) {
    case 1:
      return in * 2;
    case 2:
      return in * 3;
    default:
      return in * 4;
  }
}

This is a Godbolt link to above examples link. The link, somehow, confirms that what I wrote above are equivalent (in terms of the final compilation artifacts). But, I am still interested in a formal confirmation from C++ Spec.

mgNobody
  • 738
  • 7
  • 23

3 Answers3

4

Is the following code equivalent to the above code, compilation-wise?

The code has exactly identical observable behavior. You only need if constexpr (or a non-existing switch-equivalent) in order to allow for the non-taken branches to contain code that would be ill-formed if instantiated with the template arguments of the template specialization.

Anything regarding optimization or what machine instructions are used in the end to achieve the specified observable behavior is up to the compiler anyway and isn't specified for either version. The language standard formally only specifies the well-formedness and permitted observable behavior of programs that the compiler needs to ensure, nothing more.

Because if constexpr doesn't even cause instantiation of the non-taken branch, the compiler is of course practically sure not emit any instructions for it, while in the case with usual switch you need to rely on optimizations working that out. But if the conditions are obviously compile-time constant, then the compiler is likely going to figure out that the other branches are dead code and will remove them at a sufficiently high optimization level. This may be different if the conditions are complex and not obviously compile-time constant.

user17732522
  • 53,019
  • 2
  • 56
  • 105
  • Yes, somehow, writing a not-well-formed code inside the if-constexpr cases is one of my requirements. Not only I am interested in performance, but also some sort of ill-formed code is also expected. – mgNobody Sep 02 '23 at 00:56
  • @mgNobody *"somehow, writing a not-well-formed code inside the if-constexpr cases is one of my requirements."* -- Your question says nothing about this. It does, though, mention *"very low overhead as compiler will evaluate them at compile time"* and *"the same run-time overhead"*. I think you did not ask the question you intended to. Since it has already been answered, the recommended approach as I understand it is to upvote/accept useful answers in the context of what you did ask, then (if still desired) ask a new question focusing on "not-well-formed". – JaMiT Sep 02 '23 at 01:06
  • 1
    @mgNobody If you are going to write potentially ill-formed code in the non-taken branches, then you simply must use the `if constexpr` variant. Otherwise the program won't compile. There is no equivalent for `switch`, so you won't have a choice but to use the `if constexpr`/`else if constexpr`/`else` chain (or something more complex like calls to SFINAEed function overloads). – user17732522 Sep 02 '23 at 09:27
2

You're misunderstanding what if constexpr is for. It's not an optimization enabler, as you clearly saw yourself the compiler will optimize your ifs all the same.

Instead, what if constexpr provides is the ability to write invalid C++ code (parseable but not well-formed) that is only valid in its own branch (for example, if you're testing for a templated type), but not valid overall.

Blindy
  • 65,249
  • 10
  • 91
  • 131
  • Yes, somehow, writing a not-well-formed code inside the if-constexpr cases is one of my requirements. Not only I am interested in performance, but also some sort of ill-formed code is also expected. – mgNobody Sep 02 '23 at 00:56
  • 1
    But not for `switch`. Or if it is, you cannot do it. Remember, the code in your branches has to be *valid at compile time* once you are in that branch, and since C++ doesn't allow type based switches, purely numeric tests won't provide any additional information to the compiler. Compare that to C# which does support type-based switches (pattern matching), where you could do what you want (though it doesn't support invalid code in untouched branches). – Blindy Sep 02 '23 at 16:07
-1

Is the following code equivalent to the above code, compilation-wise?

In gcc(even in some old version like 7.1, as long as it supports template), yes.

Here's the test code. You can find compiler deleted all the dead branches and the two function are just the same in assembly.

LiuYuan
  • 127
  • 9