Declaring arrays with const variables - c++

I am trying to create a multidimensional array, however when I pass a const int value I can't compile. Error is "expression must have a constant value" for each dimension.
class Matrix {
public:
Matrix(int rowCount, int columnCount, int scalarInput) {
const int row_C = rowCount;
const int colum_C = columnCount;
const int scalar_C = scalarInput;
matrixCalculation(row_C, colum_C, scalar_C);
}
void matrixCalculation(const int i, const int j, const int s) {
int matrixArray[i][j]; // error here, i and j: "expression must have a constant value"
}
};
Thanks

Array dimensions must be compile-time constant, and const doesn't mean that.
A const object cannot change its value after initialisation, but its initialiser may be determined at runtime (e.g. const int x = rand()) so, in general, these objects are not valid candidates for array dimensions.
Introducing... constexpr.
If you plonk the keyword constexpr in front of the dimensions, you will be off to a good start. Your compiler will prevent you from breaking the contract of constexpr, and will consequently enable you to use your shiny new constexpr object as an array dimension.
Alas, in this example, you are breaking that contract already, since the inputs are non-constant. Tough cookies.
Use a vector instead.

Related

Creating array with const int size parameter in a function throws error in Visual Studio C++: expression did not evaluate to a constant

void foo(const int size) {
char array[size];
}
int main() { }
The above code throws compiler error in Visual Studio C++:
error C2131: expression did not evaluate to a constant
note: failure was caused by a read of a variable outside its lifetime
Why is size not evaluated as constant even though it's declared as const int?
But the following code compiles successfully:
int main() {
const int size{ 10 };
char array[size];
}
This compiles because size is truly constant.
int main() {
const int size{ 10 };
char array[size];
}
This however will not compile, because size is a constant variable, and not a compile time constant (there's a subtle difference)
void foo(const int size) {
char array[size];
}
The reason it won't work, is because I can call foo with differing arguments.
foo(10);
foo(42);
foo(1);
The simplest work around is to use std::vector, which is what you are trying to do...
void foo(const int size) {
std::vector<char> array(size);
}
and now 'array' will work with the same intent as your original code.
C++ is a statically typed language and char array[1] and char array[2] are different types so those types must be known at compile time.
E.g
void foo(const int size) {
char array[size];
}
int main() {
int x = std::rand() % 1000;
foo( x ); // Error
}
In this case, compiler cannot know the type of char array[size] at compile-time because the size is decided at run-time, so it is an error.
So as #Frodyne stated in comments, size of static arrays must be constant expression
The size of an array needs to be a compile time constant, not just run-time const.
Since the constant variable size is initialized to '10', the value of the size cannot be modified. The size of the array is fixed and it cannot be changed.
int size = 10; // the value of the size can be changed.

C++ pointer of array: why cannot use an array defined by indirectly computed const var in function begin(array)?

Error message in text:
I'm studying the book C++ Primer and encountering a problem listed below when coding an answer for one exercise:
#include<iostream>
#include<vector>
using namespace std;
int main() {
int i = 3;
const int ci = 3;
size_t si = 3;
const size_t csi = 3;
int ia[i];
int cia[ci];
int sia[si];
int csia[csi];
int another_a[] = {1,2,3};
int *pi = begin(ia); // error here
// no instance of overloaded function "begin" matches the argument list --
// argument types are: (int [i])
int *pci = begin(cia);
int *psi = begin(sia); // error here
// no instance of overloaded function "begin" matches the argument list --
// argument types are: (int [si])
int *pcsi = begin(csia);
int *p_ano = begin(another_a);
vector<int> v = {1,3,4};
const int m = v.size();
const size_t n = v.size();
int ma[m];
int na[n];
int *pm = begin(ma); // error here
// no instance of overloaded function "begin" matches the argument list --
// argument types are: (int [m])
int *pn = begin(na); // error here
// no instance of overloaded function "begin" matches the argument list --
// argument types are: (int [n])
system("pause");
return 0;
}
I can understand that the first two errors are because that those two arrays are not defined using an constant variable.
But why the last two, even if I have converted the size of the vector into a constant variable, the compiler still reports an error?
I'm quite confused about this, I would appreciate a lot for your kindly answer or discussion no matter it works or not.
First and foremost, you are using a compiler extension, but more on that later.
The standard begin overload which works for you is a template that accepts a reference to an array with a size that is a constant expression. In a nutshell, constant expressions are those expressions that a compiler can evaluate and know the value of during compilation.
A constant integer initialized with a constant expression like const int ci = 3;, can be used wherever a constant expression is required. So ci is, for all intents an purposes, a constant expression itself (equal to 3).
Modern C++ has a way to make such varaibles stand out as intended constant expressions, it's the constexpr specifier. So you could define ci like this:
constexpr int ci = 3;
It's exactly like your original code. But the same will not work for const int m = v.size();. Because constexpr requires a true constant expression as an initializer, unlike const. For a const variable is not necessarily a constant expression. It can just be a run-time variable that you cannot modify. And this is the case with m.
Because m is not a constant expression, what you defined is a variable length array. A C feature that is sometimes introduced as an extension by C++ compilers. And it doesn't gel with the std::begin template, which expects the array extent to be a constant expression.
Declaring arrays with non constant indexes isn't standard c++.
If you need dynamically sized arrays use std::vector.
Declaring a variable as const doesn't make it a compile time constant (required to declare a fixed sized array) it just means you can't modify it after it is declared.

C++: Expression must have a constant value when declaring array inside function [duplicate]

This question already has answers here:
How do I use arrays in C++?
(5 answers)
Closed 6 years ago.
I have looked at all the other posts with a similar topic, and none help, so please don't flag as a duplicate.
I am defining in main() a const int SIZE = 20;. Then, I pass this as an argument to my function, Mode:
int* Mode(int* numbers, int & mode, const int SIZE)
{
int occurences[SIZE];
// Calcualte mode
}
However, I get the error, expression must have a constant value.
My function call (in main) looks like this:
int* occurencesPtr = Mode(numbersPtr, mode, SIZE);
With SIZE being defined at the beginning to the literal 20.
I understand that the error is because the function's version of SIZE only acquires its value when the function is called (?), but I don't know how I could work around this.
I have even tried passing to the function a const int * const SIZEPtr = &SIZE, but that didn't work either. Help?
EDIT: I am not trying to use a variable size!! Notice that I have made SIZE a const everywhere! I just want to use that same SIZE constant to declare my array.
EDIT: Dynamic arrays are not what I need. I just want a normal, named, array, defined with a constant size value passed to the function.
There is a misconception here with what const means, probably because it's a little confusing that this works:
const int SIZE = 20;
int array[SIZE];
but this doesn't:
void foo(const int SIZE) {
int array[SIZE];
// ...
}
const int SIZE = 20;
foo(SIZE);
The issue is that the array size in an array declaration must be a core constant expression. Simplified, that means an expression that's evaluatable at compile time to be a constant. That is true in the first case (you can see that SIZE is the integral constant 20) but that is not true in the second case. There, the SIZE function parameter is just const - in the sense that it is nonmodifiable - and not a core constant expression. You can see the difference in that I can call foo() with something that is clearly unknowable until runtime:
int x;
if (std::cin >> x) {
foo(x);
}
In order to pass an argument into foo, and have that argument be used as an array bound, it is not enough to have it be const - the actual integral value must be encoded into the type (unless you call foo() as constexpr which I'm assuming is not the case here). In which case, you'd have to do something like:
template <int SIZE>
void foo() { ... }
const int SIZE = 20;
foo<SIZE>();
or:
template <int SIZE>
void foo(std::integral_constant<int, SIZE > ) { ... }
const int SIZE = 20;
foo(std::integral_constant<int, SIZE>{} );
or simply have SIZE be a global constant or otherwise accessible to foo() in a way that doesn't have to do with its arguments.
Or, there's always the simple option: use std::vector:
void foo(const int SIZE) {
std::vector<int> v(SIZE);
...
}
I understand that the error is because the function's version of SIZE only acquires its value when the function is called (?), but I don't know how I could work around this.
Option 1
Instead of defining SIZE in main, add a constexpr function. Use the constexpr function instead of passing the size.
constexpr int getSize()
{
return 20;
}
int* Mode(int* numbers, int & mode)
{
int occurences[getSize()];
// ...
}
Option 2
Use std::vector instead of array.
int* Mode(int* numbers, int & mode, int size)
{
std::vector<int> occurences[size];
// ...
}
Option 3
Use a function template.
template <size_t SIZE>
int* Mode(int* numbers, int & mode, int size)
{
int occurences[SIZE];
// ...
}
Option 4
Use a function template and std::array.
template <size_t SIZE>
int* Mode(int* numbers, int & mode, int size)
{
std::array<int, SIZE> occurences;
// ...
}
You're confusing things. A constant expression has nothing to do with const (at least not that much) ;).
let's think we are the compiler and face this function:
void foo(const int SIZE) { }
The constmerely says "we are not able to change the function-local variable SIZE inside the function body.
We need to compile it without assuming that SIZE is compile time constant. Why?
Because there is noone stoping us from doing something like:
int i{};
std::cin >> i;
foo(i);
You can pass any (matching/convertible) value to a by value const function argument.
What should happen when the compiler assumed the value passed to foo was a compile time constant expression?
If you want to pass compile time constants, use templates and while you're at it use std::array instead of T[N]:
template<std::size_t N>
void foo()
{
std::array<int, N> occurences;
}
const isn't doing what you think it's doing in your Mode function.
When const is used in function definition, const is simply telling the compiler that the function will not change the argument declared const inside of the scope of it's function. But that does not make the argument a constant, it is actually called a constant expression. Some compilers enforce this, others do not, and so will allow you to change const expressions (arguments passed with const keyword).
In order to use a globally accessible constant value which you can use, like SIZE, you'll need to declare a global constant before the function is called; which could be declared outside of main(), or at least outside the scope of all other functions but main(), if you must declare all inside main. Pass the global constant to the Mode function just as you would any other variable.
Oh, and, main() needs a return type.
I've edited the code to meet your specific constraints.
Here is a variation on your original code:
int main(){
//Declare constants first.
const int SIZE = 20; /*Could declare here instead.*/
//Declare variables next.
int *intPtr = 0; // to hold the pointer passed from Mode.
int *numbersPointer = 0;
int mode = 0;
//Define Mode (using OP's code.)
int* Mode(int* numbers, int & mode, const int size){
int occurences[size];
// Calculate mode
}
/*Now use constants, variables, and functions.*/
intPtr = Mode(numbersPointer, mode, SIZE); //Call mode.
return 0;
}

Getting 'Non-constant expression as array bound' when field is const

I'm trying to define a multidimensional array using my constant field as its dimension, but I'm getting a compilation error saying that the expression is not constant. Is there any other way to do this so I can use a constant field defined in constructor initialization list as an array dimension?
Translation for English-speaking majority:
class FunctionWave2D : public DisallowedDomainPoints
{
protected:
double th;
double l; a
double d, dd;
const int number_sqrt; //here's the constant
double **second_derivatives;
protected:
bool elasticTenstionOnly;
public:
FunctionWave2D(int number, double elasticModulus, double dampingFactor, double oscillationDampingFactor, double length)
:DisallowedDomainPoints(number * LAYER_COUNT),
th(elasticModulus), d(dampingFactor), dd(oscillationDampingFactor),
elasticTensionOnly(false),
l(length/(sqrt(number)-1)),
number_sqrt(sqrt(number))
{
second_derivatives = new double[number_sqrt][number_sqrt][LAYER_COUNT];
//(...)
In C++, the term "constant expression" specifically refers to an expression whose value is known at compile-time. It's not the same as a const variable. For example, 137 is a constant expression, but in this code:
int function(int x) {
const int k = x;
}
The value of k is not a constant expression, since its value can't be determined at compile-time.
In your case, you have a data member declared as
const int ilosc_sqrt; //here's the constant
Even though this is marked const, its value is not known at compile-time. It is initialized in the initializer list as
ilosc_sqrt(sqrt(ilosc))
This value can't be determined until the program is actually run, hence the error. (Note that the new C++11 constexpr keyword is designed, among other things, to make constant expressions a lot easier to identify in source code and to make it possible to do more advance compile-time computations with constants.)
To fix this, you will either need to split up your initialization into smaller steps:
drugie_pochodne = new double**[ilosc_sqrt];
for (int i = 0; i < ilosc_sqrt; i++) {
drugie_pochodne[i] = new double*[ilosc_sqrt];
for (int j = 0; j < ilosc_sqrt; j++) {
drugie_pochodne[j] = new double[ILOSC_WARSTW];
}
}
Or use a library like Boost.MultiArray, which supports a cleaner initialization syntax.
Hope this helps!
An array bound has to be a compile-time constant. A non-static const data member is not a compile-time constant; it gets its value at runtime, when the object is constructed.
So, basically, if you need to set the size of that array at runtime you'll have to build up all the pieces with operator new[]. Essentially,
int **data_2d = new int*[runtime_size];
for (int i = 0; i < runtime_size; ++i)
data_2d[i] = new int[runtime_size];
The extension to a 3d-array is straightforward.

cannot appear in a constant-expression

In the following c++ program:
static const int row = (dynamic_cast<int>(log(BHR_LEN*G_PHT_COUNT)/log(2)));
static const int pht_bits = ((32*1024)/(G_PHT_COUNT * G_PHT_COUNT * BHR_LEN));
unsigned char tab[pht_bits][1<<row];
I get the error message double log(double)’ cannot appear in a constant-expression.
why am I getting this problem since i have put an integer cast in front? How should i fix this?
The constant-expression that the compiler is referring to is actually the bounds of the array tab. The dimensions of statically allocated arrays have to be known at compile-time, but the value of row can't be determined until runtime, because it is evaluated using a function.
To you that are downvoting my answer. Tell me that this code does not work:
#include <stdio.h>
double log(double foo)
{
return 1.0;
}
static const int row = static_cast<int>(log(4)/log(2));
int main(void)
{
printf("%d\n", row);
return 0;
}
Original (changed from (int) to static_cast, not that it matters)
static const int row = static_cast<int>(log(BHR_LEN*G_PHT_COUNT)/log(2));