Compile time “if” syntax is available from C++17 . This makes the compiler to evaluate the given “if” expression during compilation phase. This evaluation then decides whether the body of “if” part or “else” part shall generate the code. The other part is ignored by compiler. However, compiler performs basic syntax check in the other part.
The syntax uses “constexpr” keyword just after the “if” keyword.
Weird behavior with run-time “if”
When return type of a function is “auto” type, then a regular “if” statement sometimes get into problems. For example, when in such function, both “if” and “else” parts are present, then return type should be same in both parts.
Return type deduction for function “fun” shall fail in following code, because, the “if” part returns an integer and “else” returns a non-integer. This failure happens even though, the “else” part here never needs to be used.
#include <iostream> //main header
using namespace std; //namespace
auto funda()
{
const int xvar = 1;
const int yvar = 3;
if ((xvar+yvar) == 4) //No constexpr
{
cout << "if condition" << endl;
return 7;
}
else
{
cout << "else condition" << endl;
return 2.1;
}
}
int main()
{
auto xvar = funda();
cout << xvar << endl;
return 0;
}
Output
Compile-time “if” shall resolve
The compile time “if” shall evaluate the expression at compile time and therefore, it will simply ignore the “else” part return statement.
#include <iostream> //Main header
using namespace std;//namespace
auto funda()
{
const int xvar = 1;
const int yvar = 3;
if constexpr((xvar+yvar) == 4)
{
cout << "if condition" << endl;
return 7;
}
else
{
cout << "else condition" << endl;
return 2.1;
}
}
int main()
{
auto xvar = funda();
cout << xvar << endl;
return 0;
}
Output
Same example, with no “else” part
In following example, the exit path from function “fun” is from two places. First is from the “if” body and second is from return statement in last line. Since, any of the path is possible, therefore, compiler shall again generate an error due to ambiguity in deducing return type.
#include <iostream> //main header
using namespace std; //namespace
auto funda()
{
const int xvar = 1;
const int yvar = 3;
if ((xvar+yvar) == 4) //no constexpr
{
cout << "if condition" << endl;
return 7;
}
return 2.1;
}
int main()
{
auto xvar = funda();
cout << xvar << endl;
return 0;
}
Special behavior with compile-time “if”
The compile-time “if” shall not resolve the problem as it had done in last example. This is because, still the return type deduction will be ambiguous. Please note that the condition in “if” is always going to be true. Therefore, the return statement in the “if” body shall definitely be considered to deduce function return. However, the catch is that the compiler shall also consider second return statement which is located outside any condition.
The compiler shall generate same error in following code even when compile-time if is present.
auto funda()
{
const int xvar = 1;
const int yvar = 3;
if constexpr ((xvar+yvar) == 4)
{
cout << "if condition" << endl;
return 7;
}
return 2.1;
}
With negative constexpr “if” condition
Only when the “if” condition becomes false, then compile-time “if” shall ignore the return statement in the ‘if’ part body. In following case, the compiler shall only use the return statement outside the “if” construct.
Therefore, following example shall compile and work successfully.
auto funda()
{
const int xvar = 1;
const int yvar = 3;
if constexpr ((xvar+yvar) != 4) //false at compile-time
{
cout << "if condition" << endl;
return 7;
}
return 2.1;
}
Using constexpr “if” in a template function
Just like in previous example, where the return type was “auto”, the behavior is very similar in templates.
Due to same reason, the following example shall not compile with run-time “if”.
#include <iostream> //main header
using namespace std; //namespace
template <typename T>
auto funda(T arg)
{
if (sizeof(arg) == 4) //no constexpr
{
return 7;
}
return 2.1;
}
int main()
{
auto xvar = funda<double>(3.4);
cout << xvar << endl;
return 0;
}
Compiler Output
However with compile time “if”, things will work with “fun<double>” instantiation
template <typename T>
auto funda(T arg)
{
if constexpr(sizeof(arg) == 4) //false for double
{
return 7;
}
return 2.1;
}
Two return types in two instantiation of templates
The above concept is used in following example where return type of template function is different in two different instantiations.
#include <iostream> //main header
using namespace std; //namespace
template <typename T>
auto funda(T arg)
{
if constexpr(sizeof(arg) == 4) //case of funda<int>
{
return 7;
}
else //case of funda<double>
{
return 3.1;
}
}
int main()
{
auto x1 = funda<double>(3.4);
cout << x1 << endl;
auto x2 = funda<int>(3);
cout << x2 << endl;
return 0;
}
Output