1

I get the following error when I use constant nVar instead of a number.

constants.h:

extern const unsigned int nVar;

constants.cpp:

#include "constants.h"
const unsigned int nVar = 5;

main.cpp

#pragma once
#include "constants.h"
void foo(const double q[nVar])
{
    // ...
}

Compiler:

array constant is not an integer constant before ']' token

expected ')' before ',' token

expected unqualified-id before 'const'

2 Answers 2

5

I think it happens because compiler should know array's size at compile time, but in your example value of nVar will be known only at linking time due to extern

Sign up to request clarification or add additional context in comments.

3 Comments

Correct. Move the assignment (=5) part to the header file and it will compile fine - in that case the compiler knows the size of that array.
@parry: Firstly, = 5 is not assignment, it is initialization. Secondly, simply moving = 5 to the header file will immediately trigger ODR violations (typically reported as "multiple definition" linker errors). In order to be able to specify = 5 in the header file the object has to be given internal linkage, i.e. extern has to be removed.
AndreyT Pedantry was never my interest :) It is besides the point too which was that the compiler should know the size of the array when it encounters it. I am sure we can trust OP to put the initialization and assignments in the right place - I wasn't suggesting it as a best practice, just illustrating that it would make the size visible to the compiler.
1

Firstly, you are not "initializing" the array with a constant in our example. You are specifying the size of the array. Note that in the given example the array size will be ignored anyway. Your declaration

void foo(const double q[nVar])

is actually equivalent to

void foo(const double q[])

and to

void foo(const double *q)

Secondly, in order for integral constant to be usable in a constant expression it has to be declared with an initializer. In your main.cpp your constant is declared without an initializer, which means that it can't form constant expressions and can't be used in array declarators.

Unless you really need a const object with external linkage, the proper way to declare your constant would be

const unsigned int nVar = 5;

right in the header file. Note: no extern and the initializer is specified right in the header file. The definition in constants.cpp has to be removed in that case. Technically, this will create an independent nVar object with internal linkage in each translation unit, but it won't normally occupy any memory unless used as an lvalue.

5 Comments

That doesn't sound right to me, this sounds like the rules for a static const member variable, but that doesn't apply to const global variables does it? And even static const need defining in a translation unit if you want to use it as an lvalue.
@Mooing Duck: I'm not sure what you are trying to say and what it has to do with member variables. Namespace-scope variable declaration with an initializer is always a definition, meaning that it is already defined. No need to define anything in a translation unit. As for whether it will occupy memory if used only in constant expressions - it is largely a quality-of-implementation issue.
I always thought this would result in ODR violations unless it was marked as extern.
@Mooing Duck: In C++ (as opposed to C) namespace-scope const objects have internal linkage by default, i.e. plain const is equivalent to static const. For that reason it does not produce ODR violations.
oh, never knew that. Makes sense I guess.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.