问题
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 isif
, 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()"
回答1:
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
回答2:
The difference between if constexpr
and if is whether the expression can always be executed at compile time. In your example, you are using a template argument, so it doesn't really matter which one you write. The difference can be noticed if you would have the following code:
constexpr bool is_negative(int n)
{
if (n >= 0) return false;
else return true;
}
int main(int argc, char**)
{
constexpr bool v = is_negative(1);
bool b = is_negative(argc);
return static_cast<int>(v || b);
}
For the code above, writing if constexpr
will not work. As you can call the function with a runtime value.
Again, it shouldn't matter as both code paths are valid. Normal compiler optimizations should kick in when using the function with constant values.
The real interest of if constexpr
is when only one path is valid:
template <typename T>
constexpr 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
}
If T would be an int, the code path with *t
is invalid as you can't dereference an int. However, because one uses if constexpr
instead of if
, the code in the false path only needs to be syntactically correct if it depends on the template argument.
As you are searching for a guideline, the compiler already requires: Use if constexpr
when one of the code paths is invalid. Use if
when depending on arguments.
For the case where the if-condition is calculatable at compile time with 2 valid paths, use if constexpr
to require it to be optimized even in debug builds, use if
if you want to step through it in debug builds.
If you go to extremes, the expressione could become too complex for the compiler to optimize it in a production build, in which case if constexpr
could again be interesting while in the hot path. Personally, I haven't been in this situation yet, however I haven't used it that much.
来源:https://stackoverflow.com/questions/53809853/if-vs-if-constexpr-inside-constexpr-function