#include <array>
int value1(int param) {
return param * 2;
}
constexpr int value2(int param) {
return param * 2;
}
int main() {
const int i = 10;
std::array<int, value1(i)> starr1 = {}; // 1
std::array<int, value2(i)> starr2 = {}; // 2
return 0;
}
2 is okay, but 1 gives a compile error because std::array has to make static size array. value2() returns compile-time constant value because of constexpr keyword.
So, how does the compiler infer that value2(i) is compile-time constant? Does it call the function value2() while compiling?
const int value1(int param) {
return param * 2;
}
int main() {
const int i = 10;
std::array<int, value1(i)> starr1 = {}; // 3
return 0;
}
>>> error: call to non-constexpr function ‘const int value1(int)’
Also, 3 still tgives a compile error. Is value1(i) not compile-time constant even though const keyword is applied to the function value1()?
So, how compiler infer value2(i) is compile-time constant?
It doesn't infer that. You state that explicitly when you annotate it with constexpr. It might infer that for functions not marked with constexpr, though. This still won't allow you to use their results in compile-time expressions, and is only used as an optimization strategy.
Does it call the function value2() while compiling?
In a sense, yes. It's probably closer to interpreting it directly, since I don't think any compiler actually compiles that function for the purposes of executing it during the build. What matters is that it's able to establish its result before the entire program is built and ran, and that it can use that result to e.g. determine the size of your array when generating the code.
Is value1(i) not compile constant even though const keyword is applied to the function value1()?
It's not. const only applies to the return type (and in this case, it's effectively useless), not the evaluation possibility in compile-time.
Related
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;
}
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)
This is a C++ programming code to display the values of array1 and array2 but I am getting a compile time error as 'Constant Expression Required'. Please Help
void display(const int const1 = 5)
{
const int const2 = 5;
int array1[const1];
int array2[const2];
for(int i = 1 ; i < 5 ; i++)
{
array1[i] = i;
array2[i] = i * 10;
std::cout << array1[i] << std::endl;
}
}
void main()
{
display(5);
}
In C++, const is not always constexpr. Back in the days, constexpr didn't exist, so the only way of having a compile time constant was to either use const with a literal, or to use enum, because both of these are easy for the compiler to check the value.
However, in C++11, we added constexpr, which guaranties that a constexpr variable has a value available at compile-time, and state that constexpr function can be evaluated aat compile time if all arguments are constexpr too.
In your code, you can write your variable const2 like this:
void display(const int const1=5)
{
constexpr int const2 = 5;
// ...
}
Now your code is much more expressive about what you are doing. instead of relying that the const may be available at compile time, you say "this variable has a value known at compile time, here's the value".
However, if you try to change const1, you'll get an error. Parameters, even with default value always as a value known at runtime. If the value is only known at runtime, you can't use it in template parameters or array size.
If you want your function to be able to receive the value const1 as a constant expression from where you can receive it as a template parameter, since template parameters are always known at compile time.
template<int const1 = 5>
void display()
{
constexpr int const2 = 5;
int array1[const1];
int array2[const2];
}
You will have to call your function like that:
// const1 is 5
display();
// const1 is 10
display<10>();
If you want to know more about templates, go check Function templates, or this tutorial
Why am I able to use a locally declared const int as the size of an array declaration but am not allowed to do the same with a const int passed as an argument?
For example, in the below code why do I get compiler errors only on line 2?
void f1(const int dim){
int nums[dim]; // line 2: errors
}
void f2(){
const int dim = 5;
int nums[dim]; // ok
}
Array size should be known at compile time.
const int with local variables may do not work neither if the value is not known at compile time as:
void f2(){
const int dim = bar();
int nums[dim]; // error
}
In Both case, const int tells that the value doesn't change, not that is it known at compile time.
In f2 the constant dim is known at compile time, in f1 it's not.
And since C++ doesn't have variable-length arrays the dimensions of an array must be known at compile time.
The use of const for function arguments is more of a hint to the compiler that the function will not modify the argument, allowing the compiler to for example make optimizations based on that information.
Your understanding of the const keyword is wrong. const implies that within a certain contextual scope the variable will not change, not that the variable is determined at compile time.
Since c++11 though you can use constexpr which would do what you expect. The constexpr says compiler that apart the variable is const its value can be evaluated at compile time. See: http://en.cppreference.com/w/cpp/language/constexpr
Array size should be known at compile time.
const mean the value doesn't change.
So, this is about value of 'dim` at compile time.
In first case, it is unknown. compiler don't know the value of dim at compile time. It depends on the value passed to the function.
void f1(const int dim){
int nums[dim]; // line 2: errors
}
In this case, dim value is known at compile time, so no issues.
void f2(){
const int dim = 5;
int nums[dim]; // ok
}
You can use a feature in c++ 11 for this.
define your function as constexpr.
constexpr int getDim(......)
{
.......
.......
return dim;
}
then call getDim inside f1.
void f1(){
int dim = getDim(...); //// computed at compile time
int nums[dim];
}
Note that, use of constexpr depend on your application. Further refer this.
I wondered if I could auto deduce the size of an array, which is passed as a template parameter, without (explicitly) passing its size.
The following code both compiles warning-less on g++ 4.8 and clang++ 3.3 (using -std=c++11 -Wall).
#include <iostream>
template<const int* arr>
struct array_container
{
static constexpr int val = arr[1];
array_container() {
std::cout << val << std::endl;
}
// static constexpr int arr_size = ??;
};
constexpr int one[] = { 1 };
constexpr int two[] = { 1, 2 };
int main()
{
// array_container<one> array_one;
array_container<two> array_two;
// (void) array_one;
(void) array_two;
return 0;
}
However, if I remove the two comment signs in main(), I get an out of bound error with both compilers.
Now, this is cool. Somehow the compiler knows the size of the array, though the type of const int* arr is a pointer. Is there any way to get the size of arr, e.g. to complete my comment in array_container?
Of course, you are not allowed to
Use any macros
Store the size in arr (e.g. passing an std::array as template parameter: constexpr std::array<int, 1> one = { 1 }, or using an end marker like '\0' in strings)
Use an additional template parameter for the size that can not be auto deduced (array_container<1, one> array_one).
Maybe std::extent template from <type_traits> header of C++11 standard library is what you want:
#include <iostream>
#include <type_traits>
constexpr int one[] = { 1 };
constexpr int two[] = { 1, 2 };
int main()
{
std::cout << std::extent<decltype(one)>::value << std::endl;
std::cout << std::extent<decltype(two)>::value << std::endl;
return 0;
}
Output:
1
2
template<size_t size>
constexpr size_t arraySize ( const int ( &arrayRef ) [size] ) {
return size;
}
int main(){
int A[1];
int B[2];
cout << arraySize(A) << arraySize(B);
return 0;
}
I believe something like this is what you're looking for, using array references. The syntax for declaring an array reference looks kind of like the syntax for a function pointer. This function template accepts an array reference named arrayRef, which prevents array-to-pointer decay so that compile-time info about array size is preserved. As you can see, the template argument is implicit to the compiler. Note that this can only work when the size can be deduced at compile time. Interestingly, this should still work without naming arrayRef at all. To make the above template more useful, you can add a template parameter to deduce the type of the array as well. I left it out for clarity.
Probably not, as SFINAE only happens in the immediate context, while that error comes from the requirement that UB in constexpr lead to a compile time error, which I think is not immediate. You could try a recursive SFINAE that stops on the UB, but even if it worked you would have to both check the standard and hope it does not change (as it is rather obscure and new).
The easy way is to ise s function to deduce the array size, have to explicitly pass it to the type, then store it in an auto. Probably not what you want.
There are proposals to allow type parameters to be deduced from value parameters, so you could wait for those instead.
Not a solid answer, more of an extended comment, so marked community wiki.
It is indeed possible. I found a solution using SFINAE. What it basically does is produce a substitution error if the index is out of bound (line 3 in this example):
template<class C>
static yes& sfinae(typename val_to_type<
decltype(*C::cont::data), *(C::cont::data + C::pos)>::type );
template<class C>
static no& sfinae(C );
The full source code is on github.
There are only two disadvantages:
You have to specify the type of the array (this can not be avoided)
It only works with g++ 4.8.1 and clang 3.3. g++ fails for empty strings (with a compiler bug). If someone can test for other compilers, that would be appreciated.