Declaring an array with constant size - compilation error - c++

Can someone help me to explain this:
I declare a constant in the headerfile:
const int INCRSIZE;
Then in the MIL the constant is initialized:
: INCRSIZE(10)
then later on in a function in the code (its a callback-function used in a gtkmm-GUI
bool MyWindow::on_drawing_expose_event(GdkEventExpose* event)
I allocate an array on the stack using this constant
double arrPxStep[INCRSIZE];
when I compiling i get the following errors:
-expected constant expression
- cannot allocate an array if constant size 0
- arrPxStep unknown size
I know the constant is initialzed - how come the array cannot use this constant memeber-variable that was alreade initialized in the MIL?

By the looks of the code you post, INCRSIZE is a non-static member of a class. You can't use this to initialize an array, even if the value is always set to the same in the constructor. It's just the rules.
Make INCRSIZE a static const member, defined within the class, and it will work.

It is very hard for compiler to detect, that your variable INCRSIZE is const and initialized. So it processes INCRSIZE as usual integer variable. Since you set value to this variable in constructor of your class, compiler should know something about order of calls of your functions (for you it is obvious, that constructor will be the first called function, but for compiler it is not so easy to analyze it). So, it is not included in Standard of C++ (one of reasons: because it is unnecessary and hard to support).

Related

Branch with if constexpr() on constinit variables? [duplicate]

I ran across this seemingly odd behavior. A const at top level can be used for array size declarations, but not when the const is in a class.
Here's a compiler explorer demo for MSVC, CLANG and GCC all producing an error:
expression did not evaluate to a constant
It's not really a constant if it's not const at the top level?
There's some argument to be made because top level constants can often be stored in read-only memory, while constants that are not at top level cannot. But is this behavior correct?
struct A {
const int i{ 3 };
};
int main()
{
const int ii{ 3 };
A a;
int j[a.i]{}; // C2131: expression did not evaluate to a constant
int k[ii]{};
}
Generally, you can use (meaning perform an lvalue-to-rvalue conversion on) objects with lifetime starting outside a constant expression only if they are variables marked constexpr or their subobjects (plus some other special cases, that I don't think are important here, see [expr.const]/4 for details).
That you can use a const int variable at all in a constant expression is already a very specific exception. Essentially const-qualified integral and enumeration type variables are also usable in constant expressions if you could have added constexpr to them (meaning that their initializer expression is a constant expression).
This exception is there I guess purely for historical reasons, since it had been allowed before constexpr was introduced in C++11.
Note that all of this talks about variables and their subobjects. Non-static data members are specifically not variables and the exception doesn't apply to them. With constexpr this is more obvious by not allowing it on the declaration of a non-static data member in the first place.
The historical rule was never extended to encompass other types that could be marked constexpr, so e.g. const A a; will not help although that would actually cause a to be storable in read-only memory the same way a const int would.
If an object is none of the cases mentioned above, then an lvalue-to-rvalue conversion on it in a constant expression is not allowed, since it is assumed that the value of the object is not determined at compile-time.
Now, in theory the compiler could still do some constant folding and determine that even other objects' values are definitively known at compile-time. But I think the intention is that whether or not an expression is a constant expression should be (reasonably) well-defined independently of the implementation and so shouldn't rely on how much analysis the compiler can do.
For example
A a;
A b(a);
is also guaranteed to result in b.i == 3. How far do you want to require a compiler to go back or keep track of evaluations? You would need to make some definitive specification if you want to keep the behavior consistent between compilers. But there is already a simple method to indicate that you want the compiler to keep track of the values. You just have to add constexpr:
constexpr A a;
constexpr A b(a);
Now b.i can be used as array index (whether or not it is const and whether or not it is initialized).
With the current rules, any compiler only needs to evaluate the value of objects at compile-time when it sees a constexpr variable or a const integral/enumeration type variable. For all other variables it doesn't need to keep track of values or backtrack when it sees them used in a context which requires a constant expression.
The additional effect of constexpr implying const on the variable makes sure that its value will also never be changed in a valid program and so the compiler doesn't need worry about updating or invalidating the value after the initial computation either. And whether or not an expression is a constant expression is (mostly) implementation-dependent.
ii is a compile-time constant. Its value is known at compile-time, and cannot be changed at runtime. So, ii can be used for fixed array sizes at compile-time.
A::i is not a compile-time constant. It is a non-static instance member. Its value is not known until runtime. After an A object is constructed and its i member is initialized, the value of i cannot be changed because of the const, but the caller can initialize i with whatever value it wants, eg: A a{123};, and thus different A objects can have different i values. So, i cannot be used for fixed array sizes at compile-time. But, it can be used for dynamic array sizes at runtime, via new[], std::vector, etc.
TL;DR
Your assumption that const always implies compile time constant is incorrect. See examples at the end of this answer for more details on this.
Now the problem in using a.i as the size of an array is that in standard C++, the size of an array must be a compile time constant, but since i is a non-static data member, it requires an object to be used on. In other words, after construction of the class object nonstatic data member i gets initialized, which in turn means that a.i is not a constant expression, hence we get the mentioned error saying:
expression did not evaluate to a constant
To solve this, you can make i be a constexpr static data member, as shown below. This works because using a static data member doesn't require an object instance (and hence no this pointer).
struct A {
constexpr static int i{ 3 };
};
int main()
{
const int ii{ 3 };
A a;
int j[a.i]{}; //Correct now and works in all compilers
int k[ii]{};
}
I just don't get why a regular const works in some places but not others.
Perhaps you assuming that const implies compile time constant which is a wrong assumption. An example might help you understand this better:
int i = 10; //i is not a constant expression
const int size = i; //size is not a constant expression as the initializer is not a constant expression
//------vvvv------>error here as expected since size is not a constant expression
int arr[size]{};
On the other hand if you were to make i const as shown below, the program will work fine.
const int i = 10; //note the const added here so that now i is a constant expression
const int size = i; //size is a constant expression as the initializer is a constant expression
//------vvvv------>NO ERROR HERE as expected since size is a constant expression
int arr[size]{};

I can define the length of an array using a constant, so why doesn't int d[b] work?

int a = 5;
const int b = a, c = 4;
int e[a];
int d[b];
int f[c];
The definition of f[c] is valid.
The variable b is also a constant int, but the compiler gave me the error "expression must have a constant value" for the line int d[b]. What are the differences between b and c?
what are the differences between b and c?
c has a compile time constant initialiser, while b does not. A const object with compile time constant initialiser is itself a compile time constant value.
Since I can define an lenth of an arry using a constant ,so why don't this work?
Not just any constant will do. const qualifier implies runtime constness (i.e the value may be determined at runtime but won't change throughout the lifetime of the object). Only compile time constant values can be used as array size.
You are using a non-constant variable to assign value to a constant. Therefore, that variable's value can't be determined compile time. I know you aren't changing a, but the compiler does not think like this.
The compiler diagnostic should really be compile time evaluable constant expression.
Since the original object to which b is assigned is not const, b is not a compile time evaluable constant expression, so compilation will fail as variable length arrays are not supported in standard C++.
The "const" just only means that the variable will not change at run time, and does not mean that its value can be deduced at compiling time.
I guess what you are looking for is "constexpr".
Maybe you can try it out like this:
constexpr int b = 4; // can't be assigned from a!
int d[b];
The "constexpr" instead means a "real const" and the "const" only means "non-changing var", because some historical reason.
It must be mind that a native array in c++ always is fixed-length as #Bathsheba said.
The term "constant" is really ambiguous, and the keyword const is misleading.
const means: "don't allow this object's value won't be changed after initialisation". It does not mean "compile-time constant". Its initial value can (and usually does) still come from runtime sources.
You need a compile-time constant for an array bound.
It is sometimes possible to have an object named foo that is compile-time constant, if it is const and it was initialised from a constant expression, like a literal or a constexpr thing. That's the case for c; it is not the case for b.

Expected constant in 2d array

double rainPerMonth(const int YEARS)
{
int monthYear[MONTHS][YEARS];
// ...
}
Visual Studio shows a squiggly line underneath the array declaration, saying that YEARS must be a constant when I'm creating the array. Is this an IDE issue because the variable has yet to be initialized, or am I writing this incorrectly?
MONTHS is already declared globally.
An array size must be a constant expression - that is, a value known at compile time. (Some compilers offer C-style variable-length arrays as a non-standard extension, but I don't think Visual C++ does. Even if it does, it's better not to rely on such extensions.)
A function argument isn't known at compile time, so can't be used as an array size. Your best option is here is probably
std::vector<std::array<int, MONTHS>> monthYear(YEARS);
In C++, an array must be sized at compile time. What you are attempting to do is declare one that is sized at runtime. In the function you've declared, YEARS is only constant within the scope of the function. You could call it rainPerMonth(someInt); where someInt is the result of some user input (which shows you that the result is not a compile-time constant).
Variable Length Arrays are an extension to C, but not C++. To do what you want, you can use dynamic memory, or a std::vector.
I think your problem lies in the fact that C++ wants a constant in the sense of compile-time constant to create your variable monthYear. If you pass it as a function, it need not be known at compile time? For example:
const int x=2;
const int y=3;
char xyChoice;
std::cin >> xyChoice;
if (xyChoice == 'x')
rainPerMonth(x);
else
rainPerMonth(y);
I'm unsure, but it seems to me like this would give you a constant int being passed to your function, but the compiler wouldn't know what size to create an array for before runtime?

constant function parameter as a static array size?

I am not completely sure why this isn't working
void foo(const int a=10){
const int b = 10;
int c[a];
int d[b];
}
I thought that I say to the compiler the a is constant - I even tell it that default value is 10 :).
Why is he yelling:
1>sum_floats_txt.cpp(105): error C2057: expected constant expression
1>sum_floats_txt.cpp(105): error C2466: cannot allocate an array of constant size 0
1>sum_floats_txt.cpp(105): error C2133: 'c' : unknown size
I know what it tells me, but I do not know how to do what I want to do:
- function with static array inside of size dependable on outside constant
The function is counting something and returning the time spended on the execution (doing it in RTOS).
So I want to call this function with different parameters from main. To find out for which parameter it executes the shortest.
Is the problem in the way the static arrays works? It must have a constant size in the time of compilation. So for different static arrays I must define more of them.
Possible solution is to create more functions or more static arrays with different sizes predefined. And call them one after the other, but there are thousands of different sizes.
I do not want to do the non-automatized iteration to get the best parameters! Could arguments from main passed to the function before execution help?
VS2010 + RTX64 2013 (should not be the problem)
win7
thanks!
Don't mix up const qualified and constant.
const qualified just says that you don't have the right to modify the variable.
In C++ if a const qualified variable is also a compile time constant, the construct that you are using would be allowed. Here it is a parameter to a function, so there is no way that the compiler may know a value that it would substitute at compile time.
In C, things are different. In modern C, that is C since 1999, variable length arrays with such values that are only known during execution are allowed. Unfortunately there are still C compilers that don't conform to C99. AFAIR micorsoft compilers are among these.
The const int a argument is "read only" argument. It is not necessarily a value that the compiler knows at compile time. You can use a template argument though.
template <int N = 42>
void foo() {
int myArray[N];
}
C however does allow what you wrote there, C++ doesn't but will in C++14 with "std::dynarray".

Constant value calculation

I have an hpp file with following code:
const float PixelsPerMeter = ConfigManager->Get<float>("koef", 100.0f);
inline const float Meters2Pixels(float meters) { return meters * PixelsPerMeter; }
inline const float Pixels2Meters(float pixels) { return pixels / PixelsPerMeter; }
const float ScreenArea = Pixels2Meters(ScreenSizeX) * Pixels2Meters(ScreenSizeY);
It worked before, but now ScreenArea = inf somehow. I use it from static function. I put a breakpoint in that function and print out the value of PixelsPerMeter(100.0), ScreenSizeX and ScreenSizeY. Everything is okay, but ScreenArea is calculated wrong.
When I write directly Pixels2Meters(ScreenSizeX) * Pixels2Meters(ScreenSizeY) instead of using ScreenArea constant everything works.
How it could be?
I think, the problem is with your global variable, to be precise with its initialization.
If by the time the variable has not been dynamically initialized when you call Pixels2Meters(), the variable PixelsPerMeter is statically initialized to zero, so the function Pixels2Meters() returns inf which very much implies PixelsPerMeter is zero.
But you put break points, the story could be slightly different; it is analogous to Heisenberg uncertainty principle, in the sense that when you want to see the value of PixelsPerMeter by putting breakpoints, it shows you different value than the value when there is no breakpoints.
Also note that since the variable is declared const, without extern keyword, the variable has internal linkage, which means you will have different copy of this variable in each translation unit, in case if it declared in a header file which you include in several source files. The variable's behavior is as if it is declared static.
Another important point to be noted is that this variable is initialized twice: the first initialization is called static initialization which happens at compile-time, and second initialization is called dynamic initialization which happens at runtime. In case of static initialization, the variable is initialized to zero, and that is the value which is being used which is causing the problem. To know more about it, read this:
What is dynamic initialization of object in c++?
You should also read about this:
static initialization order fiasco
When the static function is initialised is a bit complicated and may depend on system/compiler.
You probably have an issue that the ConfigManager() isn't initialised before the static function you are using it in.