Why is my expression not constant expression inside templates? [duplicate] - c++

constexpr uint32_t BitPositionToMask(int i,int Size){
static_assert(i < Size,"bit position out of range");
return 1 << i;
}
this generates:
error: non-constant condition for static assertion
on GCC 4.6.2 Am I not getting something or is this a GCC bug?

A constexpr function can also be invoked with arguments evaluated at run-time (in that case, it just gets executed just like any regular function). See, for instance, this live example.
A static_assert(), on the other hand, strictly requires its condition to be a constant expression that can be evaluated at compile time.

This answer was posted by odinthenerd (under the CC BY-SA 3.0 license) as an edit to the question Why is comparing two parameters of a constexpr function not a constant condition for static assertion?. Reposted here to conform to the site's Q&A format.
If the values are known at compile time, they can be passed as template parameters and it works as intended.
template<int i,int Size>
constexpr uint32_t BitPositionToMask() {
static_assert(i < Size,"bit position out of range");
return 1 << i;
}

Related

Why can't I pass a constexpr function to std::cout? [duplicate]

This question already has answers here:
When does a constexpr function get evaluated at compile time?
(2 answers)
Closed 2 years ago.
This code, when compiled with g++ -O3, does not seem to evaluate get_fibonacci(50) at compile time - as it runs for a very long time.
#include <iostream>
constexpr long long get_fibonacci(int num){
if(num == 1 || num == 2){return 1;}
return get_fibonacci(num - 1) + get_fibonacci(num - 2);
}
int main()
{
std::cout << get_fibonacci(50) << std::endl;
}
Replacing the code with
#include <iostream>
constexpr long long get_fibonacci(int num){
if(num == 1 || num == 2){return 1;}
return get_fibonacci(num - 1) + get_fibonacci(num - 2);
}
int main()
{
long long num = get_fibonacci(50);
std::cout << num << std::endl;
}
worked perfectly fine. I don't know exactly why this is occurring, but my guess is that get_fibonacci(50) is not evaluated at compile-time in the first scenario because items given std::cout are evaluated at runtime. Is my reasoning correct, or is something else happening? Can somebody please point me in the right direction?
Actually, both versions of your code do not have the Fibonnaci number computed at compile-time, with typical compilers and compilation flags. But, interestingly enough, if you reduce the 50 to be, say, 30, both versions of your program do have the compile-time evaluation.
Proof: GodBolt
At the link, your first program is compiled and run first with 50 as the argument to get_fibbonacci(), then with 30, using GCC 10.2 and clang 11.0.
What you're seeing is the limits of the compiler's willingness to evaluate code at compile-time. Both compilers engage in the recursive evaluation at compile time - until a certain depth, or certain evaluation time cap, has elapsed. They then give up and leave it for run-time evaluation.
I don't know exactly why this is occurring, but my guess is that get_fibonacci(50) is not evaluated at compile-time in the first scenario because items given std::cout are evaluated at runtime
Your function can be computed compile-time, because receive a compile-time know value (50), but can also computed run-time, because the returned value is send to standard output so it's used run-time.
It's a gray area where the compiler can choose both solutions.
To impose (ignoring the as-if rule) the compile-time computation, you can place the returned value in a place where the value is required compile-time.
For example, in a template parameter, in your first example
std::cout << std::integral_constant<long long, get_fibonacci(50)>::value
<< std::endl;
or in a constexpr variable, in your second example
constexpr long long num = get_fibonacci(50);
But remember there is the "as-if rule", so the compiler (in this case, also using constexpr or std::integral_constant) can select the run-time solution because this "do not change the observable behavior of the program".
Assign to a constexpr to get the compiler to spit out an error message
constexpr auto val = get_fibonacci(50);
constexpr functions are evaluated at compile time only in constexpr context, which includes assignment to constexpr variables, template parameter, array size...
Regular function/operator call is not such context.
std::cout << get_fibonacci(50);
is done at runtime.
Now, compiler might optimize any (constexpr or not, inline or not) functions with the as-if rule, resulting in a constant, a simpler loop, ...

Ternary operator evaluation rules in templates different?

Given this innocent snippet:
#include <cstdint>
template <unsigned int n> constexpr uint64_t bit = (1ull << n);
template <unsigned int n> constexpr uint64_t mask = (n == 64) ? ~0ull : bit<n> - 1;
namespace this_works_fine
{
template <unsigned int n> constexpr uint64_t bit = (1ull << n);
template <unsigned int n> constexpr uint64_t mask = []() constexpr { if constexpr (n == 64) return ~0ull; else return bit<n> - 1; }();
}
int main()
{
auto a = mask<64>;
(void)a;
}
... I expected that to "just work, zero errors, zero warnings". It's quite clear and simple and there's not much room for doing something wrong. The only thing to be aware of is that shifting more than an integer's width is UB (happens for N == 64), but that is being explicitly taken care of. It'll probably produce a warning/error for values larger than 64, but that's fine, no need for an explicit error check.
The conditional operator only evaluates either the second or the third operand based on the first operand's evaluation. So as long as the code altogether is in principle syntactically correct, we're good to go.
Now, GCC (9.1.0) tells me the following:
g++.exe -Wall -fexceptions -O2 --std=c++17 -c main.cpp -o obj\main.o
g++.exe -o lib\gcc-bug.exe obj\main.o -s
main.cpp: In instantiation of 'constexpr const uint64_t bit<64>':
main.cpp:4:73: required from 'constexpr const uint64_t mask<64>'
main.cpp:14:12: required from here
main.cpp:3:59: error: right operand of shift expression '(1 << 64)' is >= than the precision of the left operand [-fpermissive]
3 | template <unsigned int n> constexpr uint64_t bit = (1ull << n);
| ~~~~~~^~~~~
The exact same thing rewritten with if constexpr() instead compiles (and, of course, works) without any trouble. No error, no warning. No surprise. Why wouldn't it work!
While I was about to submit a bug report to GCC which is "obviously broken", it occurred to me that I might first check with version 9.2 (which isn't available for MinGW yet) as well as trunk on Godbolt, and while we're at it with Clang as well since that's just one more click.
Unsurprisingly, the other GCC versions produce the same error, but much to my surprise, Clang doesn't compile it either. It claims that (1ull << n) is not a constant expression. Which is another story, but equally stunning.
So I'm a bit unsettled there. It seems like I am not understanding the rules of the conditional operator correctly? Is there any special exception for templates or template variables where it evaluates differently?
When you are using the if constexpr then this part of the code
else return bit<n> - 1;
is not instantiated when n is equal to 64.
From the C++ Standard (9.4.1 The if statement)
2 If the if statement is of the form if constexpr, the value of the
condition shall be a contextually converted constant expression of
type bool (8.6); this form is called a constexpr if statement. If the
value of the converted condition is false, the first substatement is a
discarded statement, otherwise the second substatement, if present, is
a discarded statement. During the instantiation of an enclosing
templated entity (Clause 17), if the condition is not
value-dependent after its instantiation, the discarded substatement
(if any) is not instantiated.
Opposite to this code all parts of the code
template <unsigned int n> constexpr uint64_t mask = (n == 64) ? ~0ull : bit<n> - 1;
are instantiated. So the compiler issues an error.
Just try the following semantically equivalent code and you will get the same error.
#include <cstdint>
template <unsigned int n> constexpr uint64_t bit = (1ull << n);
template uint64_t bit<64>;
int main()
{
}

What is a value known at compile time?

I'm studying the C++ programming language and in a chapter my book introduces me the concept of constant :
A constexpr symbolic constant must be given a value that is known at compile time
What is a value known at compile time ? Why are we in need of them ?
A constant expression means an expression that can be evaluated at compile-time (i.e. before the program runs, during compilation) by the compiler.
A constant expression can be used to initialize a variable marked with constexpr (referring to the C++11 concept). Such a variable gives the compiler the hint that it could be compile-time evaluated (and that might spare precious runtime cycles), e.g.
#include <iostream>
constexpr int factorial(int n) // Everything here is known at compile time
{
return n <= 1 ? 1 : (n * factorial(n - 1));
}
int main(void)
{
constexpr int f = factorial(4); // 4 is also known at compile time
std::cout << f << std::endl;
return 0;
}
Example
If you don't provide a constant expression, there's no way the compiler can actually do all this job at compile-time:
#include <iostream>
constexpr int factorial(int n) // Everything here is known at compile time
{
return n <= 1 ? 1 : (n * factorial(n - 1));
}
int main(void)
{
int i;
std::cin >> i;
const int f = factorial(i); // I really can't guess this at compile time..
// thus it can't be marked with constexpr
std::cout << f << std::endl;
return 0;
}
Example
The gain in doing compile-time extra-work instead of run-time work is performance gain since your compiled program might be able to use precomputed values instead of having to compute them from scratch each time. The more expensive the constant expression is, the bigger is the gain your program gets.
What is a value known at compile time ?
I think it makes more sense to talk about constant expressions. A constant expression has a value that is known at compile time. Roughly speaking, it may be simply a literal, the name of another variable (whose value again is known at compile time) or a complex expression involving sub-expressions with values known at compile time.
The quote states that the initializer of a variable declared with constexpr needs to be a constant expression. In particular there are requirements an expression must satisfy to be a constant expression; Those are listed here.
Examples are
constexpr int i = 54;
constexpr float f = 684; // Compile-time conversion from int to float
constexpr int func( int i )
{
return i*47 % 23;
}
constexpr auto value = func(i * f); // Okay; constexpr function called
// with arguments that, when substituted inside,
// yield constant expressions
Sometimes a value is actually known at compile time but the expression isn't a constant one according to standard. That includes
int i = 43;
constexpr int j = reinterpret_cast<int>(i); // Shouldn't compile. (Does with GCC)
There are cases were the compiler may do constant folding - some values can be computed at compile time but don't have to be.
int i = 0;
for (int j = 1; j != 10; ++j)
i += j;
return i;
The compiler can completely eliminate the loop and initialize i with 55 (or simply return 55 and eliminate i too) as long as the behavior stays the same. This is known as the as-if rule.
It means that the program doesn't need to run in order to compute the constant. For example:
int num = 4;
You need these values in order for the compiler to place the variables in symbol tables, where they can be referenced by the program and used. In the case of constants, the compiler symbolizes constants as values that cannot be changed. So if you declare a constant as something that is determined at run-time, it will not work, because if a constant is undefined at compile-time it stays undefined. I hope this makes sense.

Why is comparing two parameters of a constexpr function not a constant condition for static assertion?

constexpr uint32_t BitPositionToMask(int i,int Size){
static_assert(i < Size,"bit position out of range");
return 1 << i;
}
this generates:
error: non-constant condition for static assertion
on GCC 4.6.2 Am I not getting something or is this a GCC bug?
A constexpr function can also be invoked with arguments evaluated at run-time (in that case, it just gets executed just like any regular function). See, for instance, this live example.
A static_assert(), on the other hand, strictly requires its condition to be a constant expression that can be evaluated at compile time.
This answer was posted by odinthenerd (under the CC BY-SA 3.0 license) as an edit to the question Why is comparing two parameters of a constexpr function not a constant condition for static assertion?. Reposted here to conform to the site's Q&A format.
If the values are known at compile time, they can be passed as template parameters and it works as intended.
template<int i,int Size>
constexpr uint32_t BitPositionToMask() {
static_assert(i < Size,"bit position out of range");
return 1 << i;
}

How to check a double's bit pattern is 0x0 in a C++11 constexpr?

I want to check that a given double/float variable has the actual bit pattern 0x0. Don't ask why, it's used in a function in Qt (qIsNull()) that I'd like to be constexpr.
The original code used a union:
union { double d; int64_t i; } u;
u.d = d;
return u.i == 0;
This doesn't work as a constexpr of course.
The next try was with reinterpret_cast:
return *reinterpret_cast<int64_t*>(&d) == 0;
But while that works as a constexpr in GCC 4.7, it fails (rightfully, b/c of pointer manipulation) in Clang 3.1.
The final idea was to go Alexandrescuesque and do this:
template <typename T1, typename T2>
union Converter {
T1 t1;
T2 t2;
explicit constexpr Converter( T1 t1 ) : t1(t1) {}
constexpr operator T2() const { return t2; }
};
// in qIsNull():
return Converter<double,int64_t>(d);
But that's not clever enough for Clang, either:
note: read of member 't2' of union with active member 't1' is not allowed in a constant expression
constexpr operator T2() const { return t2; }
^
Does anyone else have a good idea?
I want to check that a given double/float variable has the actual bit pattern 0x0
But if it's constexpr then it's not checking any variable, it's checking the value that this variable is statically determined to hold. That's why you aren't supposed to pull pointer and union tricks, "officially" there isn't any memory to point at.
If you can persuade your implementation to do non-trapping IEEE division-by-zero, then you could do something like:
return (d == 0) && (1 / d > 0)
Only +/-0 are equal to 0. 1/-0 is -Inf, which isn't greater than 0. 1/+0 is +Inf, which is. But I don't know how to make that non-trapping arithmetic happen.
It seems both clang++ 3.0 and g++ 4.7 (but not 4.6) treats std::signbit as constexpr.
return x == 0 && std::signbit(x) == 0;
It is not possible to look at the underlying bit pattern of a double from within a constant expression. There was a defect in the C++11 standard which allowed such inspection by casting via a void*, but that was addressed by C++ core issue 1312.
As "proof", clang's constexpr implementation (which is considered to be complete) has no mechanism for extracting the representation of a constant double value (other than via non-standard vector operations, and even then there is currently no way to inspect the result).
As others have suggested, if you know you will be targeting a platform which uses IEEE-754 floating point, 0x0 corresponds to the value positive zero. I believe the only way to detect this, that works inside a constant expression in both clang and g++, is to use __builtin_copysign:
constexpr bool isPosZero(double d) {
return d == 0.0 && __builtin_copysign(1.0, d) == 1.0;
}