How to initialise Const global variables based on input?

I have a few variables (say var1, var2, var 3), which I want to be const,
and whose value should be set based on some input file.

Earlier, I had just hardcoded the consts in the file, now I want to initialise based on an input file.

The variables are to be defined, outside of any function, in a file global.cpp, declared in global.h and are to be available to other files.

global.h is as follows:
1
2
3
4
5
6
7
8
#ifndef GUARD_Global_Defs
#define GUARD_Global_Defs

extern const double var1 ;
extern const double var2 ;
extern const double var3 ;

#endif 


If I had only one variable, I could do the following in global.cpp:
extern const var1 = read_file("Input_File_Name");
How do I do this cleanly when I have several consts?
Do I have to have a seperate read_file_i() version for each variable? Taking care to ignore i-1 values for read_file_i and returning the i-th value in the file?

Can I do it with just one read_file function?
Last edited on
Variables qualified with the const specifier must be known at compile time, not runtime.
Variables qualified with the const specifier must be known at compile time, not runtime.

No. ( for instance, const int c = std::rand() ; is fine.)

header:
1
2
3
extern const double& var1 ; // reference to const
extern const double& var2 ;
// ... 


implementation:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// #include header
namespace 
{
      double var1_impl ; // internal linkage
      double var2_impl ;
      // ...
      
     bool initialise_vars( /* .... */ )
     {
           // assign runtime values to var1_impl, var2_impl etc.
           return true ;
     } 

     bool initialise_them = initialise_vars( /* ... */ ) ; 
    // caveat: order of dynamic initialisation of variables at namespace scope (across translation units).
}

const double& var1 = var1_impl  ;
const double& var2 = var2_impl  ;
// ... 
Thanks JLBorges.

Could you explain the role of
1
2
3
4
namespace
{

}
and elaborate on the comment
// caveat: order of dynamic initialisation of variables at namespace scope (across translation units).

I am guessing the namespace construct ensures that the dummy initialisation bool initialise_them = is run before the const initialisations.


Also, do vars need to be references to consts? It would break if they were simply const doubles?

> Could you explain the role of namespace { ... }

We do not want names of the non-const variables (var1_impl, var2_impl etc.) to be part of the interface of the component. So we place these encapsulated implementation details in an unnamed namespace. Names placed in an unnamed namespace is not programmatically visible outside the translation unit; they have internal linkage.


> elaborate on the comment // caveat: order of dynamic initialisation

See: http://www.parashift.com/c++-faq/static-init-order.html


> Also, do vars need to be references to consts? It would break if they were simply const doubles?

If they were const double values, they would have to be initialised at the point of their definition; as in the first post: const double var1 = read_file( "Input_File_Name" );. This would be quite clumsy if there are many of these variables.
Thanks.

> elaborate on the comment // caveat: order of dynamic initialisation

See: http://www.parashift.com/c++-faq/static-init-order.html


Do you mean that I have to watch out that the dynamic initialisation routines do not refer to other global objects defined in other files (as illustrated in the article)?
If the initialisation routines only refer to objects defined in global.cpp, I should be fine?


> Also, do vars need to be references to consts? It would break if they were simply const doubles?

If they were const double values, they would have to be initialised at the point of their definition; as in the first post: const double var1 = read_file( "Input_File_Name" );. This would be quite clumsy if there are many of these variables.


but if I have
1
2
const double var1 = var1_impl;  
const double var2 = var2_impl;

isn't this a definition, where they are being assigned at the point of definition?
> If the initialisation routines only refer to objects defined in global.cpp, I should be fine?

Yes. And if there is no code in other translation units that refer to these objects before control reaches main().



> but if I have
1
2
> const double var1 = var1_impl;  
> const double var2 = var2_impl;

> isn't this a definition, where they are being assigned initialised at the point of definition?

Yes, these would be definitions. However, within the same translation unit, objects at namespace scope are initialised in the same order in which they are defined.

In any case, you do not have:
1
2
const double var1 = var1_impl;  
const double var2 = var2_impl;

Instead you have:
1
2
const double& var1 = var1_impl;  
const double& var2 = var2_impl;
Thanks for the explanations!

For the last point:
1
2
const double var1 = var1_impl;  
const double var2 = var2_impl;


1
2
const double& var1 = var1_impl;  
const double& var2 = var2_impl;


Both ways are definitions with initialisations at the point of definition.
I am confused as to why the first way would be incorrect, for what we are trying to do.

However, within the same translation unit, objects at namespace scope are initialised in the same order in which they are defined.

But the const definitions are outside the namespace scope, so I dont get this comment..
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// #include header
namespace 
{
      double var1_impl ; // internal linkage
      double var2_impl ;
      // ...
      
     bool initialise_vars( /* .... */ )
     {
           // assign runtime values to var1_impl, var2_impl etc.
           return true ;
     } 

     bool initialise_them = initialise_vars( /* ... */ ) ; 
    // caveat: order of dynamic initialisation of variables at namespace scope (across translation units).
}

const double var1 = var1_impl  ;
const double var2 = var2_impl  ;
// ... 
> I am confused as to why the first way would be incorrect, for what we are trying to do.

The first creates two different objects for each value, one of which is a non-modifiable copy of the other.
The second does not create another object; a reference is just an alias.

The first will not be incorrect for what we are trying to do. Because:
-- the variables are not expected to be modified after initialise_vars() is called.
-- double is a copyable type (unlike, say, an array or a stream).
-- double is inexpensive (small footprint and trivial copy, unlike, say, a vector).
-- initialisation of a second object does not have external side effects (like, say, appending a record to a file).


> the const definitions are outside the namespace scope,

The const definitions are outside the unnnamed namespace; but they are still at namespace scope.
At the global namespace scope.
The outermost declarative region of a translation unit is also a namespace, called the global namespace.
A name declared in the global namespace has global namespace scope (also called global scope).
Last edited on
If I understood your post right, I could define vars as consts, like the first way:
1
2
3
4
...
...
const double var1 = var1_impl  ;
const double var2 = var2_impl  ;

and it would be ok since all of the following conditions hold:
-- double is a copyable type (unlike, say, an array or a stream).
-- double is inexpensive (small footprint and trivial copy, unlike, say, a vector).
-- initialisation of a second object does not have external side effects (like, say, appending a record to a file).

However, if any of the above conditions were to be not true, I must use references.


If this is correct, then I am confused by your earlier comment
> Also, do vars need to be references to consts? It would break if they were simply const doubles?

If they were const double values, they would have to be initialised at the point of their definition; as in the first post: const double var1 = read_file( "Input_File_Name" );. This would be quite clumsy if there are many of these variables.

But if I understood correctly, I need not use const double var1 = read_file( "Input_File_Name" ). I could use your routine (without references)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// #include header
namespace 
{
      double var1_impl ; // internal linkage
      double var2_impl ;
      // ...
      
     bool initialise_vars( /* .... */ )
     {
           // assign runtime values to var1_impl, var2_impl etc.
           return true ;
     } 

     bool initialise_them = initialise_vars( /* ... */ ) ; 
    // caveat: order of dynamic initialisation of variables at namespace scope (across translation units).
}

const double var1 = var1_impl  ;
const double var2 = var2_impl  ;
// ... 
Last edited on
> But if I understood correctly, I need not use const double var1 = read_file( "Input_File_Name" ).
> I could use your routine (without references)

Yes.
Topic archived. No new replies allowed.