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

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.

Related

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.

const variable not recognized as array dimension

long AnsiString::pos(const char* plainString) const {
const size_t patternLength = strlen(plainString);
if (patternLength == 0) return -1;
size_t stringLength = count;
int partialMatch[patternLength]; // int* partialMatch = new int[patternLength];
KMPBuildPartialMatchTable(plainString, partialMatch);
int currentStringCharacter = 0;
int currentPatternCharacter = 0;
while (currentStringCharacter < stringLength) {
if (currentPatternCharacter == -1) {
currentStringCharacter++;
currentPatternCharacter = 0;
}
else if (items[currentStringCharacter] == plainString[currentPatternCharacter]) {
currentStringCharacter++;
currentPatternCharacter++;
if (currentPatternCharacter == patternLength) return currentStringCharacter - currentPatternCharacter;
} else {
currentPatternCharacter = partialMatch[currentPatternCharacter];
}
}
// delete(partialMatch);
return -1;
}
I get an error in the implementaation of this claas method using visual c++.
int partialMatch[ patternLength ] ; // expression must have a constant value
(I'm using VS in other language so you could find some differences).
I declared patternLength as a constant as you can see. A solution is commented in the ccode but i don't want to use dynamic memory allocation. Some idea ?
Array sizes must be known at compile time.
A const variable does not ensure that. The const qualifier ensures that the variable cannot be modified once it is initialized.
It is possible for the value of const variable to be known at compile time. If a compiler can detect that, then the variable can be used to define the size of an array.
More often, the value of a const variable is not known at compile time. It is initialized with a value at run time, which can't be changed after the variable is initialized. That does not make it fit for use to define the size of an array.
If you want to be able to use the variable at compile time, use constexpr instead. The compiler will do its best to evaluate the value at compile time. It will fail if the value of the variable cannot be evaluated at compile time.
The size N in an array declaration T[N] must be a compile-time constant-expression.
std::size_t const a{42}; // is one,
std::size_t foo{std::rand() % 100};
std::size_t const b{foo}; // is not, because it depends on foo
Marking something const does not make it a constant expression per se. It makes it a read only. The right hand side of your statement should satisfy constexpr function requirements, which the strlen(plainString) expression does not. You could make your own function that is evaluated during compile time:
constexpr size_t constexprlength(const char* s) {
return strlen(s);
}
and use that instead:
constexpr size_t patternLength = constexprlength(plainString);
int partialMatch[patternLength];
VLAs and character arrays are evil. Use std::vector and std::string instead.

'Constant Expression Required' Error while keeping formal argument as a constant

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

Declaring arrays with const variables

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.

How to convert int to const int to assign array size on stack?

I am trying to allocate a fixed size on stack to an integer array
#include<iostream>
using namespace std;
int main(){
int n1 = 10;
const int N = const_cast<const int&>(n1);
//const int N = 10;
cout<<" N="<<N<<endl;
int foo[N];
return 0;
}
However, this gives an error on the last line where I am using N to define a fixed
error C2057: expected constant expression.
However, if I define N as const int N = 10, the code compiles just fine.
How should I typecast n1 to trat it as a const int?
I tried : const int N = const_cast<const int>(n1) but that gives error.
EDIT : I am using MS VC++ 2008 to compile this... with g++ it compiles fine.
How should I typecast n1 to treat it as a const int?
You cannot, not for this purpose.
The size of the array must be what is called an Integral Constant Expression (ICE). The value must be computable at compile-time. A const int (or other const-qualified integer-type object) can be used in an Integral Constant Expression only if it is itself initialized with an Integral Constant Expression.
A non-const object (like n1) cannot appear anywhere in an Integral Constant Expression.
Have you considered using std::vector<int>?
[Note--The cast is entirely unnecessary. Both of the following are both exactly the same:
const int N = n1;
const int N = const_cast<const int&>(n1);
--End Note]
Only fixed-size arrays can be allocated that way. Either allocate memory dynamically (int* foo = new int[N];) and delete it when you're done, or (preferably) use std::vector<int> instead.
(Edit: GCC accepts that as an extension, but it's not part of the C++ standard.)