Static assert that passes if expression is not known at compile time - c++

I want to implement my_static_assert that slightly differs from c++17 single-parametric static_assert: if condition inside my_static_assert is not known at compile time, it should pass.
The second my_static_assert in the following example should pass but if I would use static_assert it will fail.
#include <iostream>
int x, y;
constexpr int f1() { return 0; }
constexpr int f2() { return 0; }
int f3() { return x; }
int f4() { return y; }
constexpr int sum(int a, int b) { return a + b; }
int main() {
std::cin >> x >> y;
// it should fail
my_static_assert(sum(sum(f1(), f2()), sum(f1(), f1())) != 0);
// it should pass
my_static_assert(sum(sum(f1(), f2()), sum(f4(), sum(f3(), f1()))) != 0);
}
If you want to know why this question arised:
I am building expressions using leaf functions f1,f2,f3,f4 and operations on the expression nodes: sum,mul,div,sub. Leafs that are known at compile time contain value that is always 0.
I am trying to check that my expressions contain at least one element that is not known at compile time.

If you are willing to commit to a compiler with GNU extensions, it's possible. So be warned.
It takes two overloads and a helper macro:
template<std::size_t N>
constexpr void assert_helpr(int(&)[N]) = delete;
void assert_helpr(...) {}
#define my_static_assert(...) do { \
__extension__ int _tmp [(__VA_ARGS__) + 1]; \
assert_helpr(_tmp); \
} while(0)
It works as follows:
The macro grabs your token soup and treats it like an integral expression. +1 is to avoid pathological zero cases.
If the expression is a constant expression, we get a standard array. Otherwise we get a VLA.
Now we call one of two overloaded functions. Overload resolution will always choose a c var-arg function last. If what we got was a regular array, the first, deleted overload is chosen, and the assertion fails.
If we got a VLA, the second overload is chosen and the assertion passes.
I haven't tested it thoroughly, but it seems to work on both Clang and GCC. See it live.
#Artyer was kind enough to share a solution based on this approach on godbolt.
Here's a reduction of that code to this problem:
template<std::size_t N>
constexpr std::false_type assert_helpr(int(&)[N]);
constexpr std::true_type assert_helpr(...);
#define my_static_assert(...) do { \
__extension__ int _tmp[(__VA_ARGS__) + 1]; \
static_assert(decltype(assert_helpr(_tmp)){}, #__VA_ARGS__); \
} while(0)
Same use of overloading, except this time we grab an actual result type from the call via decltype, and proceed to create a true compile time Boolean constant out of it.
This allows direct use of static_assert, and as a nice to have feature, we can pass it the stringified token soup to get an indication in the error of the expression that failed.

Related

constexpr, or not constexpr, that is the question

I was playing around with constexpr in C++ and noticed a strange behavior that I wish to understand. Consider this code from 5.19 section of Standard.
constexpr int f1(int k) {
constexpr int x = k; // error: x is not initialized by a
// constant expression because lifetime of k
// began outside the initializer of x
return x;
}
As error states, lifetime of k began outside the initializer of x, thus we can't be sure that x will be a constant expression.
And here the another version of the same function.
constexpr int f1(int k) {
return k;
}
This one is totally fine and usable. So question is why, here also, the lifetime of k began outside of initializer of return value, or not, or this is because of RVO and technically if just follow the Standard this also should be an error?
And also another question, from which this one actually arise. I was trying to write constexpr IPv4 class. For that purpose I've used constructor with std::string_view. So I was able to have this in compile time using gcc 10.3 and -std=c++20
constexpr IPv4 myIP{"192.168.0.0"};
constexpr size_t count = myIP.countOfDots(); // calls std::count which is constexpr in C++20
Now I want to validate that IP is correct, so I need to check count of dots to be equal to 3, which I can easily do here by
if constexpr (count != 3)
The question is how to organize this into some function, which will also allow me to do such a check in compile time for any given IP, basically I want something like this
constexpr bool validateIP(const IPv4& ip);
And as in the example above, I can't just have this in that function
constexpr size_t count = ip.countOfDots();
So is it possible to do the way I want?
A function that's constexpr means that the function potentially can be evaluated at compile-time. The function must however also be callable with a run-time value, and produce a run-time result.
A variable that's constexpr has to be a compile time constant. Period.
What that means for your validateIP function is that you don't need to make count constexpr. You can write a function and mark it as constexpr.
When you call the function with a compile time constant, it will get evaluated at compile time.
If you call it with a run time value it will get evaluated at run time.
#include <string_view>
#include <iostream>
constexpr bool validateIP(const std::string_view& ip) {
int count = 0;
for (auto& c : ip) {
if (c == '.') {
++count;
}
}
return count == 3;
}
int main()
{
// Assigning the value to a constexpr is not needed to make the function
// be evaluated at compile time, but it proves that it is in this case
constexpr auto isValid1 = validateIP("123.456.789.0");
std::cout << isValid1;
}

Using the number of statements in a function as a constant for memory allocation

I have a function which executes a bunch of tests. Whenever a new test is created, the function gets one or two more lines. And - the result is pushed back into an array. So it goes something like this (simplified):
void foo(int *results) {
auto index { 0 };
results[i++] = test_1(some, args, here);
results[i++] = test_1(some, other_args, here);
results[i++] = test_2(some, args, here);
results[i++] = test_3(some, args, here);
// etc. etc.
}
void bar() {
auto results = new int/* magic */];
foo(results);
}
I want to use the number of statements in this function to allocate space for the results (the line in bar()). I cannot use a dynamically-reallocated structure like an std::vector or a list etc. - since I am precluded from allocating any memory due to hardware restrictions.
Now, I could just manually count the lines - and this would work. But then whenever I add another test I would have to remember to update the magical constant.
Is there some way to do the counting with the result usable for the "magic" expression?
Note: Since I'm a scrupulous man with no dignity, I am willing to stoop to the use of macros.
Speaking of macro hackery:
#include <iostream>
#define ADD_TEST(X) do { results[i++] = (X); (void)__COUNTER__; } while (0)
const int foo_start = __COUNTER__;
void foo(int *results) {
int i = 0;
ADD_TEST(100);
ADD_TEST(200);
ADD_TEST(300);
}
const int foo_end = __COUNTER__;
int main() {
int results[foo_end - foo_start - 1];
foo(results);
for (int i : results) {
std::cout << i << '\n';
}
}
It's slightly awful and __COUNTER__ is a non-standard extension in GCC and other compilers, but hey, it works.
The advantage is that it doesn't use any fancy C++ features, so in principle it should be compatible with older compilers and even C.
As you haven't specified any language version, though, did tag it with constexpr, I've solved this making use of C++17. This without any dirty macros. Instead, I'm relying on CTAD (Constructor template argument deduction).
First of all, I've assumed your functions are constexpr. That way, everything can be done at compile-time. (In the resulting code, you don't even see memory being used for the array.
constexpr int test_1(int a, int b, int c)
{
return a + b + c;
}
constexpr int test_2(int a, int b, int c)
{
return a * b * c;
}
This isn't strictly needed, however, it can move unneeded calculations to compile time. It also allows propagating constexpr upto the final variable. That way, you could guarantee that none of the calculations will happen at run-time.
static constexpr auto myArr = createFilledArray();
However, the most important part is CTAD. A new C++17 feature that allows deducing the template arguments of your class based on the values that are passed at the constructor.
Instead of first creating an array, I create the array directly with all the different values that you pass to it. Since you haven't provided any arguments in your example, I assume they are known at compile time, which is again required for the constexpr waterfall. However, more importantly, I assume the number of elements is known at compile time.
By constructing all arguments when calling the constructor of std::array, there is no need for specifying its template arguments (note also the auto as return type). This gets deduced as std::array<int, 3> for this example.
constexpr auto createFilledArray(){
std::array a
{
test_1(1, 2, 3),
test_1(4, 5, 6),
test_2(7, 8, 9),
};
return a;
}
int main(int, char**)
{
return myArr.size(); // Returns 3
}
Code at compiler explorer
From what I'm aware, there is a proposal for C++20 that is intended to make std::vector constexpr. However, none of the compilers I've tested at compiler explorer support this. This will most likely allow you to write code based on std::vector and use that at compile time. In other words, the allocated memory that represents your data, will be part of your executable.
A quick attempt of what your code could look like can be found here at compiler explorer. (However, it ain't compiling at this point)

How to understand constexpr in this example?

I'm trying to understand the meaning of constexpr when applied to functions. In the example below the program compiles and runs but I don't understand how the function sum(int n) can be deduced at compile time as n is not known until run time. I'm using VS 2017 with latest updates.
The program compiles whether constexpr is included or not.
#include <iostream>
constexpr int sum(int n)
{
return (n <= 0) ? 0 : n + sum(n-1);
}
int main()
{
int i;
std::cin >> i;
std::cout << sum(i) << std::endl;
return 0;
}
I expected the compiler to error that sum(int n) is not a constant expression. Or is constepxr just a hint to the compiler like "inline", that it is free to ignore?
I expected the compiler to error that sum(int n) is not a constant expression.
constexpr int sum(int n); means that the function can be evaluated at compile time. It doesn't have to be. You can call it at runtime without any issues, which makes sense to not force programmers to duplicate code when they need identical functionality at runtime as well as at compile time.
With C++20, you'll be able to trigger the error you were expecting by qualifying the function with the new keyword consteval instead of constexpr.
consteval int sum(int n)
{
// As before...
}
int i;
// determine i at runtime...
sum(i); // Error! Not evaluated at compile time.
You can have a look at P1073 for this feature. This proposal has been approved for the next standard.
The constexpr keyword says that the function must be evaluated at compile time, if it's called in a constexpr context.
Consider:
constexpr int sum(int n)
{
return (n <= 0) ? 0 : n + sum(n-1);
}
int main()
{
int i;
std::cin >> i;
constexpr int s1 = sum(4); // OK, evaluated at compile time
int s2 = sum(i); // OK, evaluated at run time
constexpr int s3 = sum(i); // Error, i cannot be evaluated at compile time
int s4 = sum(4); // OK, execution time depends on the compiler's mood
}
Here, s3 is constexpr and so it's initializer needs to be evaluated at compile time. Hence the error.
If this feature weren't there, you would have to write two versions of your function, one for compile time use and the other for run-time use.
See it yourself on the Compiler Explorer.
Also note that constexpr implies inline for functions.
Here is what my perspective is
constexpr, ensures that the constant must be a compile-time constant
Thus
constexpr double pi (3.5); // is Okay because resolution is at compile time
and this
// Should be Okay be cause the resolution of **sum** is at compiletime
// evaluation however is run-time dependent
constexpr int sum(int n)
{
return (n <= 0) ? 0 : n + sum(n-1);
}
Another example is something like this
constexpr int compute(int x) {
return x+1;
}
int foo[compute(15)];

How to check at compile time that a function may be called at compile time? [duplicate]

Since the extended versions of constexpr (I think from C++14) you can declare constexpr functions that could be used as "real" constexpr. That is, the code is executed at compile time or can behave as inline functions. So when can have this program:
#include <iostream>
constexpr int foo(const int s) {
return s + 4;
}
int main()
{
std::cout << foo(3) << std::endl;
const int bar = 3;
std::cout << foo(bar) << std::endl;
constexpr int a = 3;
std::cout << foo(a) << std::endl;
return 0;
}
The result is:
7
7
7
So far so good.
Is there a way (possibly standard) to know inside foo(const int s) if the function is executed at compile time or at runtime?
EDIT: Also is it possible to know at runtime if a function was evaluated at compile time?
C++20 introduces is_constant_evaluated, defined in header <type_traits>, which addresses this issue.
constexpr int foo(int s)
{
if (std::is_constant_evaluated()) // note: not "if constexpr"
/* evaluated at compile time */;
else
/* evaluated at run time */;
}
Note that here the ordinary if is used instead of if constexpr. If you use if constexpr, then the condition has to be evaluated at compile time, so is_constant_evaluated always returns true, rendering the test useless.
The technique listed works, but since it uses static_assert it is not sfinae friendly. A better way (in theory, you'll see what I mean) to do this is to check whether a function is noexcept. Why? Because, constant expressions are always noexcept, even if the functions are not marked as such. So, consider the following code:
template <class T>
constexpr void test_helper(T&&) {}
#define IS_CONSTEXPR(...) noexcept(test_helper(__VA_ARGS__))
test_helper is constexpr, so it will be a constant expression as long as its argument is. If it's a constant expression, it will be noexcept, but otherwise it won't be (since it isn't marked as such).
So now let's define this:
double bar(double x) { return x; }
constexpr double foo(double x, bool b) {
if (b) return x;
else return bar(x);
}
foo is only noexcept if the x is a constant expression, and b is true; if the boolean is false then we call a non constexpr function, ruining our constexpr-ness. So, let's test this:
double d = 0.0;
constexpr auto x = IS_CONSTEXPR(foo(3.0, true));
constexpr auto y = IS_CONSTEXPR(foo(3.0, false));
constexpr auto z = IS_CONSTEXPR(foo(d, true));
std::cerr << x << y << z;
It compiles, great! This gives us compile time booleans (not compile failures), which can be used for sfinae, for example.
The catch? Well, clang has a multi-year bug, and doesn't handle this correctly. gcc however, does. Live example: http://coliru.stacked-crooked.com/a/e7b037932c358149. It prints "100", as it should.
I think the canonical way to do that is with static_assert. static_asserts are evaluated at compile time, so they will break the build if their condition is false.
#include <iostream>
constexpr int foo(const int s) {
return s + 4;
}
int main()
{
std::cout << foo(3) << std::endl;
const int bar = 3;
std::cout << foo(bar) << std::endl;
constexpr int a = 3;
std::cout << foo(a) << std::endl;
static_assert(foo(3) == 7, "Literal failed");
static_assert(foo(bar) == 7, "const int failed");
static_assert(foo(a) == 7, "constexpr int failed");
return 0;
}
clang++ -std=c++14 so1.cpp compiles fine for me, showing that everything works as expected.
If you can use C++20, there is std::is_constant_evaluated which does exactly what you want. std::is_constant_evaluated is typically implemented using a compiler intrinsic.
This is called __builtin_is_constant_evaluated in GCC and clang, so you can implement your own "safe" wrapper around it, even in C++17 and lower.
// if C++20, we will need a <type_traits> include for std::is_constant_evaluated
#if __cplusplus >= 202002L
#include <type_traits>
#endif
constexpr bool is_constant_evaluated() {
#if __cplusplus >= 202002L
return std::is_constant_evaluated();
#elif defined(__GNUC__) // defined for both GCC and clang
return __builtin_is_constant_evaluated();
#else
// If the builtin is not available, return a pessimistic result.
// This way callers will implement everything in a constexpr way.
return true;
#endif
}
Note that this builtin is still relatively new (GCC 9.0+) so you might also want to detect the compiler version.
Within a constexpr function, you couldn't tell if you are being evaluated in a constexpr context prior to c++20. Since c++20, this functionalty was added -- constexpr bool std::is_constant_evaluated() will tell you if you are being called in a constexpr context.
Outside a constexpr function, there are a number of ways to determine if a call to a function with a certain set of arguments would be evaluated in a constexpr context. The easiest would be to use the result in a context requiring constexpr.
Assuming your constexpr expression returns a non-void integral or pointer type (including function pointer):
#define CONSTEXPR_EVAL(...) \
std::integral_constant< \
std::decay_t<decltype(__VA_ARGS__)>, \
__VA_ARGS__ \
>::value
then CONSTEXPR_EVAL( bar(foo, true) ) will fail to compile if bar(foo, true) cannot be evaluated at compile time, and if it can be evaluated at compile time it returns that value.
Other tricks involving noexcept (a function evaluated at compile time is noexcept) can work (see #NirFriedman's answer).
Based on the information in this discussion, I crafted the following minimal example:
template <class T>
constexpr void test_helper(T &&) {}
#define IS_CONSTEXPR(...) noexcept(test_helper(__VA_ARGS__))
constexpr void test(){
static_assert(IS_CONSTEXPR(10), "asdfadsf");
constexpr const int x = 10;
static_assert(IS_CONSTEXPR(x), "asdfadsf");
int y;
static_assert(IS_CONSTEXPR(y), "asdfadsf");
}
int main(){
test();
return 0;
}
To my disappointment, It it fails to compile at each of the static_asserts. see https://www.godbolt.org/z/Tr3z93M3s
Sorry for spoiling the party, but there is certainly no standard way of doing this. Under the as-if rule, the compiler could emit code that calculates the result at run time even in such cases where it has already been forced to calculate it at compile time in a different context. Anything that can be done at compile time can be done again at run time, right? And the calculation has already been proven not to throw.
By extension, then, any standard-compliant IS_REALLY_CONSTEXPR or is_really_constexpr check cannot disprove that the exact same call, or for that matter, the value of the exact same constexpr symbol involves a run time calculation.
Of course there usually isn't any reason to repeat a calculation at run time that can be done or even has already been done at compile time, but the question was about telling whether the compiler uses the precalculated result, and there isn't one.
Now you did say possibly standard, so in effect your best bet is probably to test one of the provided solutions with your compiler of choice and hope that it behaves consistently. (Or reading the source code if it is open/public source and you are so inclined.)

Is it possible to test if a constexpr function is evaluated at compile time?

Since the extended versions of constexpr (I think from C++14) you can declare constexpr functions that could be used as "real" constexpr. That is, the code is executed at compile time or can behave as inline functions. So when can have this program:
#include <iostream>
constexpr int foo(const int s) {
return s + 4;
}
int main()
{
std::cout << foo(3) << std::endl;
const int bar = 3;
std::cout << foo(bar) << std::endl;
constexpr int a = 3;
std::cout << foo(a) << std::endl;
return 0;
}
The result is:
7
7
7
So far so good.
Is there a way (possibly standard) to know inside foo(const int s) if the function is executed at compile time or at runtime?
EDIT: Also is it possible to know at runtime if a function was evaluated at compile time?
C++20 introduces is_constant_evaluated, defined in header <type_traits>, which addresses this issue.
constexpr int foo(int s)
{
if (std::is_constant_evaluated()) // note: not "if constexpr"
/* evaluated at compile time */;
else
/* evaluated at run time */;
}
Note that here the ordinary if is used instead of if constexpr. If you use if constexpr, then the condition has to be evaluated at compile time, so is_constant_evaluated always returns true, rendering the test useless.
The technique listed works, but since it uses static_assert it is not sfinae friendly. A better way (in theory, you'll see what I mean) to do this is to check whether a function is noexcept. Why? Because, constant expressions are always noexcept, even if the functions are not marked as such. So, consider the following code:
template <class T>
constexpr void test_helper(T&&) {}
#define IS_CONSTEXPR(...) noexcept(test_helper(__VA_ARGS__))
test_helper is constexpr, so it will be a constant expression as long as its argument is. If it's a constant expression, it will be noexcept, but otherwise it won't be (since it isn't marked as such).
So now let's define this:
double bar(double x) { return x; }
constexpr double foo(double x, bool b) {
if (b) return x;
else return bar(x);
}
foo is only noexcept if the x is a constant expression, and b is true; if the boolean is false then we call a non constexpr function, ruining our constexpr-ness. So, let's test this:
double d = 0.0;
constexpr auto x = IS_CONSTEXPR(foo(3.0, true));
constexpr auto y = IS_CONSTEXPR(foo(3.0, false));
constexpr auto z = IS_CONSTEXPR(foo(d, true));
std::cerr << x << y << z;
It compiles, great! This gives us compile time booleans (not compile failures), which can be used for sfinae, for example.
The catch? Well, clang has a multi-year bug, and doesn't handle this correctly. gcc however, does. Live example: http://coliru.stacked-crooked.com/a/e7b037932c358149. It prints "100", as it should.
I think the canonical way to do that is with static_assert. static_asserts are evaluated at compile time, so they will break the build if their condition is false.
#include <iostream>
constexpr int foo(const int s) {
return s + 4;
}
int main()
{
std::cout << foo(3) << std::endl;
const int bar = 3;
std::cout << foo(bar) << std::endl;
constexpr int a = 3;
std::cout << foo(a) << std::endl;
static_assert(foo(3) == 7, "Literal failed");
static_assert(foo(bar) == 7, "const int failed");
static_assert(foo(a) == 7, "constexpr int failed");
return 0;
}
clang++ -std=c++14 so1.cpp compiles fine for me, showing that everything works as expected.
If you can use C++20, there is std::is_constant_evaluated which does exactly what you want. std::is_constant_evaluated is typically implemented using a compiler intrinsic.
This is called __builtin_is_constant_evaluated in GCC and clang, so you can implement your own "safe" wrapper around it, even in C++17 and lower.
// if C++20, we will need a <type_traits> include for std::is_constant_evaluated
#if __cplusplus >= 202002L
#include <type_traits>
#endif
constexpr bool is_constant_evaluated() {
#if __cplusplus >= 202002L
return std::is_constant_evaluated();
#elif defined(__GNUC__) // defined for both GCC and clang
return __builtin_is_constant_evaluated();
#else
// If the builtin is not available, return a pessimistic result.
// This way callers will implement everything in a constexpr way.
return true;
#endif
}
Note that this builtin is still relatively new (GCC 9.0+) so you might also want to detect the compiler version.
Within a constexpr function, you couldn't tell if you are being evaluated in a constexpr context prior to c++20. Since c++20, this functionalty was added -- constexpr bool std::is_constant_evaluated() will tell you if you are being called in a constexpr context.
Outside a constexpr function, there are a number of ways to determine if a call to a function with a certain set of arguments would be evaluated in a constexpr context. The easiest would be to use the result in a context requiring constexpr.
Assuming your constexpr expression returns a non-void integral or pointer type (including function pointer):
#define CONSTEXPR_EVAL(...) \
std::integral_constant< \
std::decay_t<decltype(__VA_ARGS__)>, \
__VA_ARGS__ \
>::value
then CONSTEXPR_EVAL( bar(foo, true) ) will fail to compile if bar(foo, true) cannot be evaluated at compile time, and if it can be evaluated at compile time it returns that value.
Other tricks involving noexcept (a function evaluated at compile time is noexcept) can work (see #NirFriedman's answer).
Based on the information in this discussion, I crafted the following minimal example:
template <class T>
constexpr void test_helper(T &&) {}
#define IS_CONSTEXPR(...) noexcept(test_helper(__VA_ARGS__))
constexpr void test(){
static_assert(IS_CONSTEXPR(10), "asdfadsf");
constexpr const int x = 10;
static_assert(IS_CONSTEXPR(x), "asdfadsf");
int y;
static_assert(IS_CONSTEXPR(y), "asdfadsf");
}
int main(){
test();
return 0;
}
To my disappointment, It it fails to compile at each of the static_asserts. see https://www.godbolt.org/z/Tr3z93M3s
Sorry for spoiling the party, but there is certainly no standard way of doing this. Under the as-if rule, the compiler could emit code that calculates the result at run time even in such cases where it has already been forced to calculate it at compile time in a different context. Anything that can be done at compile time can be done again at run time, right? And the calculation has already been proven not to throw.
By extension, then, any standard-compliant IS_REALLY_CONSTEXPR or is_really_constexpr check cannot disprove that the exact same call, or for that matter, the value of the exact same constexpr symbol involves a run time calculation.
Of course there usually isn't any reason to repeat a calculation at run time that can be done or even has already been done at compile time, but the question was about telling whether the compiler uses the precalculated result, and there isn't one.
Now you did say possibly standard, so in effect your best bet is probably to test one of the provided solutions with your compiler of choice and hope that it behaves consistently. (Or reading the source code if it is open/public source and you are so inclined.)