Saturday, 25 February 2017

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





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.


Answer



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 
void foo() { ... }

const int SIZE = 20;
foo();


or:




template 
void foo(std::integral_constant ) { ... }

const int SIZE = 20;
foo(std::integral_constant{} );


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 v(SIZE);
...
}

No comments:

Post a Comment

c++ - Does curly brackets matter for empty constructor?

Those brackets declare an empty, inline constructor. In that case, with them, the constructor does exist, it merely does nothing more than t...