Do I need to put constexpr after else-if?

  • A+
Category:Languages

Inspired by this answer, I tried to copy and paste (and add testing in main()) this code:

template<typename T> std::tuple<int, double> foo(T a) {     if constexpr (std::is_same_v<int, T>)         return {a, 0.0};      else if (std::is_same_v<double, T>)         return {0, a};      else         return {0, 0.0}; }  int main() {     auto [x, y] = foo("");      std::cout << x << " " << y; } 

This is very straightforward - if T is deduced as int, we want to return a tuple of [a, 0.0]. If T is deduced as double, we want to return a tuple of [0, a]. Otherwise, we want to return [0, 0.0].

As you can see, in the main() function, I am calling foo with const char* argument, which should result in x and y being 0. That is not the case.

While trying to compile it, I encountered a strange error:

error: could not convert '{0, a}' from '<brace-enclosed initializer list>' to 'std::tuple<int, double>'

And I was like what?. Why on earth would I want that... I specifically used std::is_same to enable return {0, a} only when the type of a is deduced as double.

So I quickly ran to cppreference on if-constexpr. At the bottom of the page, above Notes, we can see this snippet of code:

extern int x; // no definition of x required int f() { if constexpr (true)     return 0; else if (x)     return x; else     return -x; } 

I thought to myself oookay..? I can't really see what's wrong with the original code. They use the same syntax and semantics....

But I was curious. I was curious if maybe something odd (at that time) might fix that issue, so I changed the original code to:

template<typename T> std::tuple<int, double> foo(T a) {     if constexpr (std::is_same_v<int, T>)         return {a, 0.0};      else if constexpr (std::is_same_v<double, T>) // notice the additional constexpr here         return {0, a};      else         return {0, 0.0}; }  int main() {     auto [x, y] = foo("");      std::cout << x << " " << y; } 

And voilà! The code compiled and executed as expected. So, my question is - Do we need to put constexpr after every if statement in if-else block in these kind of situations? Or is it just my compiler? I am using GCC 7.3.

 


Do we need to put constexpr after every if statement in if-else block in these kind of situations?

Yes. The else-if block is a lie :), there are only if blocks and else blocks. This is how your code is seen by the compiler:

if constexpr (std::is_same_v<int, T>)     return {a, 0.0}; else // {     if (std::is_same_v<double, T>)         return {0, a};     else         return {0, 0.0}; // } 

else if (/*...*/) is just a formatting convention that everyone uses. As such, you can clearly see that the second constexpr is needed.

Comment

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: