I want to specialize a template for a certain GUID, which is a 16 byte struct. The GUID object has internal linkage, so I can't use the address of the object itself, but I thought I could use the contents of the object, since the object was a constant. But this doesn't work, as illustrated by this example code:
struct S
{
int const i;
};
S const s = { 42 };
char arr[s.i];
Why isn't s.i a constant if s is? Any workaround?
The initialization of the struct s can happen at run time. However, the size of an array must be known at compile time. The compiler won't (for sure) know that the value of s.i is known at compile time, so it just sees you're using a variable for something you shouldn't be. The issue isn't with constness, it's an issue of when the size of the array is needed.
You may be misunderstanding what const means. It only means that after the variable is initialized, it is never changed. For example this is legal:
void func(int x){
const int i = x*5; //can't be known at compile-time, but still const
//int array[i]; //<-- this would be illegal even though i is const
}
int main(){
int i;
std::cin >> i;
func(i);
return 0;
}
To get around this limitation, in C++11 you can mark it as constexpr to indicate that the value can be determined at compile time. This seems to be what you want.
struct S
{
int const i;
};
int main(){
constexpr S const s = { 42 };
char arr[s.i];
return 0;
}
compile with:
$ c++ -std=c++11 -pedantic file.cpp
in C99, what you're doing is legal, the size of an array does not need to be known at compile time.
struct S
{
int const i;
};
int main(){
struct S const s = { 42 };
char arr[s.i];
return 0;
}
compile with:
$ cc -std=c99 -pedantic file.c
At least most of the time, const really means something much closer to "read-only" than to "constant". In C89/90, essentially all it means is "read-only". C++ adds some circumstances in which it can be constant, but it still doesn't even close to all the time (and, unfortunately, keeping track of exactly what it means when is non-trivial).
Fortunately, the "workaround" is to write your code the way you almost certainly should in any case:
std::vector<char> arr(s.i);
Bottom line: most use of a built-in array in C++ should be considered suspect. The fact that you can initialize a vector from a non-constant expression is only one of many advantages.
Related
#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.
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)
I get an error on line 6 (initialize my_foo to foo_init) of the following program and I'm not sure I understand why.
typedef struct foo_t {
int a, b, c;
} foo_t;
const foo_t foo_init = { 1, 2, 3 };
foo_t my_foo = foo_init;
int main()
{
return 0;
}
Keep in mind this is a simplified version of a larger, multi-file project I'm working on. The goal was to have a single constant in the object file, that multiple files could use to initialize a state structure. Since it's an embedded target with limited resources and the struct isn't that small, I don't want multiple copies of the source. I'd prefer not to use:
#define foo_init { 1, 2, 3 }
I'm also trying to write portable code, so I need a solution that's valid C89 or C99.
Does this have to do with the ORGs in an object file? That initialized variables go into one ORG and are initialized by copying the contents of a second ORG?
Maybe I'll just need to change my tactic, and have an initializing function do all of the copies at startup. Unless there are other ideas out there?
In C language, objects with static storage duration have to be initialized with constant expressions, or with aggregate initializers containing constant expressions.
A "large" object is never a constant expression in C, even if the object is declared as const.
Moreover, in C language, the term "constant" refers to literal constants (like 1, 'a', 0xFF and so on), enum members, and results of such operators as sizeof. Const-qualified objects (of any type) are not constants in C language terminology. They cannot be used in initializers of objects with static storage duration, regardless of their type.
For example, this is NOT a constant
const int N = 5; /* `N` is not a constant in C */
The above N would be a constant in C++, but it is not a constant in C. So, if you try doing
static int j = N; /* ERROR */
you will get the same error: an attempt to initialize a static object with a non-constant.
This is the reason why, in C language, we predominantly use #define to declare named constants, and also resort to #define to create named aggregate initializers.
It's a limitation of the language. In section 6.7.8/4:
All the expressions in an initializer for an object that has static storage duration shall be constant expressions or string literals.
In section 6.6, the spec defines what must considered a constant expression. No where does it state that a const variable must be considered a constant expression. It is legal for a compiler to extend this (6.6/10 - An implementation may accept other forms of constant expressions) but that would limit portability.
If you can change my_foo so it does not have static storage, you would be okay:
int main()
{
foo_t my_foo = foo_init;
return 0;
}
2021: For who reaches this post because of arm-none-eabi-gcc.exe compile error on STM32 MCUs:
Change your toolchain to gnu-tools-for-stm32.9-2020-q2-update.
From GCC V8.1+, nested constant initializer is supported and the code below will be compiled.
const int a = 1;
const int b = a +1;
typedef struct foo_t {
int a, b, c;
} foo_t;
const foo_t foo_init = { 1, 2, 3 };
foo_t my_foo = foo_init;
int main()
{
return 0;
}
arm-none-eabi-gcc.exe in gnu-tools-for-stm32.7-2018-q2-update is based on gcc v7.3.1 and the code above will not compile! But gnu-tools-for-stm32.9-2020-q2-update uses gcc v9.3.1 and will compile.
For more info see these:
Why "initializer element is not a constant" is... not working anymore?
and
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=69960#c18
Just for illustration by compare and contrast
The code is from http://www.geeksforgeeks.org/g-fact-80/
/The code fails in gcc and passes in g++/
#include<stdio.h>
int initializer(void)
{
return 50;
}
int main()
{
int j;
for (j=0;j<10;j++)
{
static int i = initializer();
/*The variable i is only initialized to one*/
printf(" value of i = %d ", i);
i++;
}
return 0;
}
This is a bit old, but I ran into a similar issue. You can do this if you use a pointer:
#include <stdio.h>
typedef struct foo_t {
int a; int b; int c;
} foo_t;
static const foo_t s_FooInit = { .a=1, .b=2, .c=3 };
// or a pointer
static const foo_t *const s_pFooInit = (&(const foo_t){ .a=2, .b=4, .c=6 });
int main (int argc, char **argv) {
const foo_t *const f1 = &s_FooInit;
const foo_t *const f2 = s_pFooInit;
printf("Foo1 = %d, %d, %d\n", f1->a, f1->b, f1->c);
printf("Foo2 = %d, %d, %d\n", f2->a, f2->b, f2->c);
return 0;
}
There are basically two sorts of initialization: at compile time, and at run time.
The initialization for static-storage variable belongs to the compile-time initialization. Note that the static-storage variable includes:
global variable without the static keyword
global variable with the static keyword
local variable with the static keyword
But what is the principle behind this rule?
In my mind it's simple to explain.
Before the completion of compilation, the values of these variables would be stored into the executable file. And at that time no code can run!
gcc 7.4.0 can not compile codes as below:
#include <stdio.h>
const char * const str1 = "str1";
const char * str2 = str1;
int main() {
printf("%s - %s\n", str1, str2);
return 0;
}
constchar.c:3:21: error: initializer element is not constant
const char * str2 = str1;
In fact, a "const char *" string is not a compile-time constant, so it can't be an initializer. But a "const char * const" string is a compile-time constant, it should be able to be an initializer. I think this is a small drawback of CLang.
A function name is of course a compile-time constant.So this code works:
void func(void)
{
printf("func\n");
}
typedef void (*func_type)(void);
func_type f = func;
int main() {
f();
return 0;
}
I had this error in code that looked like this:
int A = 1;
int B = A;
The fix is to change it to this
int A = 1;
#define B A
The compiler assigns a location in memory to a variable. The second is trying a assign a second variable to the same location as the first - which makes no sense. Using the macro preprocessor solves the problem.
This code will not compile:
#ifndef RemoteControl_h
#define RemoteControl_h
#include "Arduino.h"
class RemoteControl
{
public:
RemoteControl();
~RemoteControl();
static void prev_track();
static void next_track();
static void play_pause_track();
static void mute();
static void vol_up();
static void vol_down();
void respond(int code);
void add_code(int code, void (*func)());
private:
boolean active = true;
struct pair {
int _code;
void (*_func)();
};
const int max = 1000;
int database_length = 0;
pair database[max]; //This line doesn't compile unless I use a literal constant instead of "max"
};
#endif
But if I put the section below in the constructor for the class instead it works fine.
const int max = 1000;
int database_length = 0;
pair database[max];
Am I not allowed to declare an array within a class in c++ and use a virtual constant as the length? I am working in arduino if that makes a difference, but I expect that I am not understanding something with the c++ language since this is a standard .h file. Oh and the problem isn't the .cpp file because I completely removed it with the same results: compiles with literal constant length but not virtual constant length.
In C or C++,try using malloc() in stdlib.h, cstdlib for c++. Don't forget free()
const int max = 1000;
struct pair *ptr = malloc(sizeof(pair) * max); // allocated 1000 pairs
free(ptr); // when the amount of memory is not needed anymore
Let me first clear a few things up for you.
In C, a const variable is considered as const-qualified, it is not a compile-time constant value (unlike an integer literal, which is a compile time constant value). So, as per the rules for normal array size specification, you cannot even use a const variable in this case.
In C, we may have the provision to use VLA which enables us to use syntax like pair database[max] even if max is not a const variable but that is again some optional feature of the compiler (as per C11).
In C++, we can use a const variable as the size of array, as in C++, a const variable is a compile time constant.
So, to answer your question:
In C, your code will be ok if your compiler supports VLA. and even if max is not const.
In C++, there is no VLA, but it maybe supported as a gnu extension. If max is const, it will be ok.
The easiest fix is to just take the
const int max = 1000;
out of the class and put it above the class.
Even better would be to ensure that it is a compile-time constant like so:
constexpr int max = 1000;
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.