Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

if vs if constexpr inside constexpr function

Recently I modify some if constexpr into if in my constexpr functions and found they still work fine and can be evaluated when compile time. Here is a minimum case:

template<int N>
constexpr bool is_negative()
{
    if constexpr  (N >= 0) return false;
    else  return true; 
}
int main()
{
    constexpr  bool v = is_negative<1>();
}

live demo

In the case above, N must be known at compile time because it is non-type template parameter, so if constexpr works fine here. However, it is a constexpr function, so, iirc, it is possible to get a return value even though I replace if constexpr with if:

template<int N>
constexpr bool is_negative()
{
    if  (N >= 0) return false;
    else  return true; 
}
int main()
{
    constexpr  bool v = is_negative<1>();
}

live demo

From cppref, all of the requirements in A constexpr function must satisfy the following requirements: don't mention if. So, IIUC, it should be implementation defined behavior whether constexpr function contain if to be evaluted at compile time even though all related variable is known at compile time(like is_negative above).

So, my conclusion is:

  • Before c++17, we don't have if constexpr, so the choice is if, which means it is not guaranteed to get our constexpr functions get evaluted at compile time, all depend on compiler implementation
  • After c++17, if constexpr is preferred if we want constexpr functions get evaluated at compile time.

All above is my personal thoughts, maybe something important missed/misunderstand, feel free to correct me. The question is still unchanged: if and if constexpr, which should be prefered for constexpr functions which expected to be evaluated at compile time.

references: - What is Allowed in a constexpr Function? - Difference between "if constexpr()" Vs "if()"

like image 238
Chen Li Avatar asked Dec 11 '22 04:12

Chen Li


1 Answers

Before c++17, we don't have if constexpr, so the choice is if, which means it is not guaranteed to get our constexpr functions get evaluted at compile time, all depend on compiler implementation

The fact that an if statement is not constexpr does not mean it can't be evaluated at compile time, as part of a constexpr expression. In your example, v is evaluated at compile time in both cases, because it is required to be: it's a constant expression. That's not implementation defined.

After c++17, if constexpr is prefered if we want constexpr functions get evaluated at compile time.

Constexpr if statements were introduced to solve a problem. Getting constexpr functions to get evaluated at compile time is not that problem.

Here is an example where a constexpr if is required instead of a simple if (taken from cppreference):

template <typename T>
auto get_value(T t) {
    if constexpr(std::is_pointer_v<T>)
        return *t; // deduces return type to int for T = int*
    else
        return t;  // deduces return type to int for T = int
}

Try removing the constexpr keyword and see what happens (demo).

Also, note that you can always solve that problem using other methods, but if constexpr has the advantage of conciseness. For instance, here's an equivalent get_value using tag dispatching:

template<typename T>
auto get_value_impl(T t, std::true_type) {
    return *t;
}
template<typename T>
auto get_value_impl(T t, std::false_type) {
    return t;
}

template<typename T>
auto get_value(T t) {
    return get_value_impl(t, std::is_pointer<T>{});
}

Demo

like image 127
Nelfeal Avatar answered Jan 03 '23 22:01

Nelfeal