C++ Referencing extern const within a namespace - c++

I am trying to use the constant int SIZE that is declared in the TaxConstants.hpp namespace TAXCONSTANTS in other places in my project. When I try to compile, I get "undefined reference to 'SIZE' everywhere that SIZE is referenced.
file TaxConstants.hpp
#ifndef TaxConstants_hpp
#define TaxConstants_hpp
namespace TAXCONSTANTS
{
extern const int SIZE = 4; // I have tried with and without extern
}
#endif //TAXCONSTANTS_HPP
main.cpp
#include <iostream>
#include "TaxConstants.hpp"
using namespace std;
using namespace TAXCONSTANTS;
int main()
{
extern const int SIZE;
// This is a struct defined in another file. It is a sample of my use for SIZE. I left out the #include above to simplify things.
taxPayer payers[SIZE];
//More code
return 0;
}
Additional info: this is a school project and my teach has made it a requirement to declare constants in the file TaxConstants.hpp in the namespace TAXCONSTANTS.
There are 5 files in total, the file with my functions is having the same undefined reference to SIZE error.
I have spent hours looking up similar explanations on the extern function and namespaces, but most of the suggestions are against doing this in the first place an offer another solution. I, unfortunately can not use them. Other errors people had were getting "multiple decorations" which I am not having.
EDIT
See Brians explanation below for better detail.
What I needed to do was define
const int SIZE = 4;
within the TaxConstants.hpp file in namespace TAXCONSTANTS.
Then remove
'extern const int SIZE;'
from my main file and instead reference SIZE by TAXCONSTANTS::SIZE everywhere I wanted to use size.
This is basic namespace stuff that I completely forgot about.

If you define SIZE without the extern keyword, it will have internal linkage since it is const. You can refer to it inmain.cpp as TAXCONSTANTS::SIZE. This is recommended since the compiler will be able to inline the value wherever SIZE is used.
If you define SIZE with the extern keyword, it will have external linkage and it should not be in a header, unless you want multiple definition errors. You should instead define it in a .cpp file which will be linked into the rest of the program. In this case there will be only one copy of SIZE in the entire program. You should avoid this approach (preferring instead the approach without extern) unless for some reason you actually need to have only one copy of SIZE in the entire program.
In both cases, SIZE will be a member of the TAXCONSTANTS namespace.
Your attempt to redeclare SIZE inside main does not do what you think it does! The following inside main:
extern const int SIZE;
actually has the effect of declaring SIZE in the global namespace. Since there is no definition of SIZE in the global namespace, you get undefined reference errors at link time. It is not the correct way to refer to the SIZE variable defined in TAXCONSTANTS.

Multiple problems with the entire approach.
Your
extern const int SIZE;
in main is a declaration of const int object SIZE from global namespace - ::SIZE. This SIZE has absolutely nothing to do with your TAXCONSTANTS::SIZE. Such global ::SIZE object is not defined in your program, which is why you get "undefined reference" error.
Since you already declared TAXCONSTANTS::SIZE in the header file, you don't need to redeclare SIZE again in main. Why are you doing this?
Just remove the declaration from main and use SIZE from TAXCONSTANTS either through using namespace TAXCONSTANTS or by specifying a qualified name TAXCONSTANTS::SIZE.
The declaration you have in the header file is actually a definition. Including this header file into multiple translation units will result in another error: multiple definitions of the same object with external linkage.
If you want to declare a global constant object, you have to keep a mere non-defining declaration in the header file
namespace TAXCONSTANTS
{
extern const int SIZE; // declaration, not definition
}
and move the definition into one of implementation files
namespace TAXCONSTANTS
{
extern const int SIZE = 4; // definition
}
However, it appears that you are planning to use this constant as an Integral Constant Expression (as array size in array declaration). An extern const int constant declared without an initializer will not work for that purpose.
Just forget about extern and declare a normal constant with internal linkage in the header file
namespace TAXCONSTANTS
{
const int SIZE = 4; // definition with internal linkage
}
and then just use in everywhere it is needed
using namespace TAXCONSTANTS;
int main()
{
taxPayer payers[SIZE];
...
}
or
// no 'using namespace TAXCONSTANTS;'
int main()
{
taxPayer payers[TAXCONSTANTS::SIZE];
...
}

Related

Correct way of initializing a class globally in C++

I know global is bad but just as a practice, is this the correct way to initialize a global class used between multiple object files?
Header 1.h
class test {
int id;
public:
test(int in){
id = in;
}
int getId(){
return id;
}
};
extern test t;
File 1.cc:
#include <iostream>
#include "1.h"
int main(){
std::cout << t.getId() << std::endl;
return 0;
}
File 2.cc:
#include "1.h"
test t(5);
Now what if instead of extern I use the static approach globally static test t(0); in the header?
Correct me if I'm wrong but that would compile fine however I would have 2 different unrelated copies of the same t in both object files and the final binary? Is that bad? Or does the linker sort it out to eliminate multiple copies?
There are global instances, not global classes.
What you have is a global instance. And yes, this sounds about right, until you get to multiple global instances which depend upon each other. Then the real fun will start.
Defining a variable as 'static' at global level means the variable will be defined in the compilation unit only (i.e. the '.o' file) and the symbol won't be exported by the compiler.
In other words: yes, there will be multiple variables with the same name but only visible to functions on the same compilation unit.
Besides, 'invisible' doesn't mean 'inaccessible'. You still can provide access to the variable. For example:
1.h
struct Test { int value; }; // Class definition
Test& get_t(); // Function declaration
1.cc
#include "1.h"
static Test t; // Variable declared as 'static'
Test& get_t() { return t; };
2.cc
#include "1.h"
#include <iostream>
int main()
{
std::cout << get_t().value << std::endl; // Static variable accessed
}
I use the static approach globally static test t;?
But your test class needs an int in parameter for the constructor, so you want:
static test t(0); // or whatever int you want
If you turn the extern to static in the header, you would define a static variable in each compilation unit in which the header is imported. So classes in different cpp files would no longer "communicate" via t, since each would have theirs. This is very error prone.
In addition, adding the definition of a static in a header is an extremely bad practice. When someone includes a header, one does not expect that it will create variables.
Including the declaration of t as extern is an acceptable practice. But be aware that if the header has a general purpose, this might reduce its reusability other projects.
More information of interest for you:
Must read: C++ Core Guidelines about source files
Must read: Guidelines for writing headers
StackOverflow: When are global variables recommended
Why global variables should be avoided if possible and when are they ok
If you put a variable declaration outside of any function, you're declaring the variable as 'global'. Ex:
1.cc
int this_is_global;
From here on you can use the variable in any function of '1.cc'.
For using the same variable in any other file, the compiler will need to know about it:
2.cc
extern int this_is_global;
Here, the keyword extern tells the compiler that the variable is declare somewhere else, letting the task of finding it to the linker.
If you miss to add the extern keyword here, the compiler will treat it as a new variable, and the linker will have two variables with the same name and will emit an error. All of your source files of your project except the first one will need the extern keyword to avoid duplicate symbols.
So common practice is to add the 'extern' declaration in an include file:
1.cc
int this_is_global;
1.h
extern int this_is_global;
2.cc
#include "1.h"
On the other side, the static keyword tells the compiler not to export the symbol. In other words: the variable will exists only in the source file it is declared. You could declare it once per source file and there will be different variables with the same name. Ex:
1.h
static int my_var;
1.cc
#include "1.h"
2.cc
#include "1.h"
This way, you'll end having two variables 'my_var' and changes to any of them won't affect the other.

c++ extern constant int for array size

I have the following three files in my code (with most of the code removed. This is just to isolate the issue).
global.h:
//global.h
#ifndef GLOBAL_H
#define GLOBAL_H
extern const int ARRAYSIZEX;
extern const int ARRAYSIZEY;
extern const int ARRAYSIZEZ;
#endif //GLOBAL_H
global.cpp:
//global.cpp
#include "global.h"
const int ARRAYSIZEX = 5;
const int ARRAYSIZEY = 2;
const int ARRAYSIZEZ = 4;
main:
//main
#include "global.h"
using namespace std;
someType mySomeTypeArray[ARRAYSIZEX][ARRAYSIZEY][ARRAYSIZEZ];
int main(int argc, char **argv)
{
//...
}
Compiling gives me three errors at the declaration of mySomeTypeArray.
error: array bound is not an integer constant before ']' token
I want to keep my global variable and array size definitions in global.h/cpp for this application, just for organization, so that all my configuration parameters are in one place. What's the proper way to achieve what I'm trying to do?
Thanks
Your declaration is failing because array sizes need to be evaluated at compile-time and your encapsulation scheme is actually hiding the values from the compiler. This is true because compilers work on individual translation units. While compiling main.cpp your compiler sees only extern const int ARRAYSIZEX thanks to the include statement, but not the value which is visible in a separate translation unit so it can't figure out the memory layout.
While const variables can used as array sizes in some contexts, the language provides the more appropriate constexpr qualifier which comes with a set of restrictions that enforce its compile-time evaluation and suitability for array sizes. I recommend always using it when appropriate because it will point you to the error in situations such as this. In this case, you would get a compiler error because an extern constexpr declaration is ill-formed which hints at the proper solution: to hold the values for compile-time constants directly inside the header file.
global.h
constexpr int ARRAYSIZEX = ...;
constexpr int ARRAYSIZEY = ...;
constexpr int ARRAYSIZEZ = ...;
main.cpp
#include "global.h"
someType mySomeTypeArray[ARRAYSIZEX][ARRAYSIZEY][ARRAYSIZEZ];
The problem here is extern int x means "x is defined in another file, but don't worry about the particulars, all you need to know is it's an int". This is normally good enough, except when the compiler needs to know right there and then what x is.
Since that's defined in a whole other file it can't. That file must be compiled before it knows, and the result of that compilation, due to the way C++ works, can't impact the compilation of this file.
You'll need to declare that as a const int in a header if you want to share those values. extern int won't cut it.
Although this is a trivial example, there's really no reason to go down the extern road at all. Just define the values in the header file as regular const int.
Array size must be specified by an integer constant expression. A const int object can be used in an integer constant expression if and only if it declared with an initializer and that initializer is also an integer constant expression. Your ARRAYSIZE... variables do not satisfy that requirement. In main they are declared without an initializer. You cannot use ARRAYSIZE... variables as array sizes in main.
Unless you have a specific requirement to give these variables external linkage, simply declare (and define) them in the header as
const int ARRAYSIZEX = 5;
const int ARRAYSIZEY = 2;
const int ARRAYSIZEZ = 4;
These object will have internal linkage though, which is different from what your original variant attempts to do.
If really want to give them external linkage, declare them as inline extern const in the header
inline extern const int ARRAYSIZEX = 5;
inline extern const int ARRAYSIZEY = 2;
inline extern const int ARRAYSIZEZ = 4;
Since inline by itself prevents const from imposing internal linkage, extern is entirely optional in these declarations. And since inline const combination can be replaced with constexpr (as #M.M noted in the comments), you can achieve the same effect with just
constexpr int ARRAYSIZEX = 5;
constexpr int ARRAYSIZEY = 2;
constexpr int ARRAYSIZEZ = 4;
The problem here is that ARRAYSIZEX, ARRAYSIZEY and ARRAYSIZEZ are not the compile time constants. They are constants - so their values can't be changed but their values are not known to compiler.
In C++ the compilation process consists of 3 basic steps.
Preprocessing of all source files done by preprocessor.
Compilation for every translation unit (.cpp file) done by compiler. For every translation unit compiler creates an object file.
Linking of all object files done by linker. The output is an executable file.
In C++ the keyword extern for compiler means that the variable is 'somewhere' defined. The compiler doesn't know the variable's real address but by placing keyword extern it's assured that the variable really exists and the linker will be able to find its address by its name when creating the executable file.
The problem here is that compiler in step 2 wants to create the object file but it doesn't known how big the array is going to be because it doesn't know the value of these constants. Yes, linker in step 3 will finally find them when putting together all object files but it's too late for compiler. So it generates that error.
The solution is simple. Use already mentioned constexpr keyword and initialize all variables with initializers. The keyword constexpr marks compile time constants - constants that have to be initialized in initializers and are known to compiler.

extern variable and array declare issue c++

I have a problem with an extern variable and an array declaration with it.
How to declare an array with global variable which located not in the declarable file.
file1.cpp
const int size = 10;
mainfile.cpp
extern const int size;
void main()
{
int mas[size];
}
int mas[size];
This line has an issue.
Please any guess??
You can't. An array size must be a constant expression; if it's a variable, then that variable must be const and initialised in the same translation unit, so that its value is available for use as a constant.
If you want to share the value between multiple translation units, define it in a header and include that.
First of all constants have internal linkage. Thus these declarations
file1.cpp
const int size = 10;
and
mainfile.cpp
extern const int size;
refer to different entities.
The constant declared in file1.cpp is not visible outside its corresponding compilation unit.
According to the C++ Standard (3.5 Program and linkage)
3 A name having namespace scope (3.3.6) has internal linkage if it is
the name of
— a non-volatile variable that is explicitly declared const or
constexpr and neither explicitly declared extern nor previously
declared to have external linkage; or
In mainfile the value of size is not specified so the compiler will issue an error for statement
int mas[size];
becuase the size of an array shall be a compile-time constant expression.
The simplest solution is to place the constant definition
const int size = 10;
in some common headet file that will be included in each translation unit where there is a reference to the constant.
int mas[size];
This line has an issue. Please any guess??
As other users pointed, the issue could be that you're trying to create a Variable Lenght Array which is something not allowed in C++ (but almost enter in C++14 as Dynamic Arrays*).
Some compilers accept VLA as an extension (no standard) so I'm guessing that you're using one that doesn't have this extension or have this extension disabled.
Don't worry, you have workarrounds anyway...
#define (don't do that)
Assuming that the issue is the VLA, if we ensure the size as a compile-time value, the problem is solved so...
// file1.hpp <-- This is now a HEADER not a CPP
#define SIZE 10
// mainfile.cpp
#include "file1.hpp"
void main()
{
int mas[SIZE]; // accepted, equivalent to int mas[10].
}
constexpr
C++11 introduced the constexpr* keyword which can be used to achieve your goal
// file1.hpp <-- This is now a HEADER not a CPP
constexpr int size() { return 10; }
// mainfile.cpp
#include "file1.hpp"
void main()
{
int mas[size()];
}
enum
Enumerations are compile-time constants, so you can use them this way:
// file1.hpp <-- This is now a HEADER not a CPP
enum constant { size = 10 };
// mainfile.cpp
#include "file1.hpp"
void main()
{
int mas[constant::size];
}
*If someone found a better link, please let me know.
C++ does not allow the size of arrays to be specified at runtime. In your example of course it is specified at link time, but that is no help to the compiler.
If you are using a C++14 compiler however, and on certain other compilers (such as gcc) you can do this, but it is less portable than allocating the memory dynamically, and lest convenient than a std::vector<>.
For reference: https://isocpp.org/wiki/faq/freestore-mgmt#dynamic-array-len

Is there any possible use of using extern variable in a file that is not included in any other file?

I've encountered many examples on the web, that have extern int x in main.c, where the main function lies.
The only use of extern I'm aware of, is to make a declaration in another file, and use it in another file, after defining it.
Like :
a.h : extern int x;
a.c : int x = 5;
main.c :
#include "a.h" // and start using x
The 1st case seems redundant to me.
So,
Is there any possible use of using an extern variable in a file that is not included in any other file?
extern tells the compiler that x exists in a different module and should be linked from elsewhere. Putting it in main.c directly just avoids pulling in a header (which would be included in-line anyways)
Just like in a header, x still needs to exist in another .c module where it isn't defined extern.
extern variable has basically two functions one is to use the variable in the other file and the other is to access global variables as in the following code.
int x=10;
int main()
{
int x=20;
cout<<x; //refers to x=20
if(x==20)
{
extern int x;
cout<<x; //refers to the global x that is x=10
}
}
Of course. Using extern in a file lets you use that variable in that file. It doesn't have to be included anywhere else.
The use of extern causes the object to have external linkage; to
instantiate a template with a object (and not a value or a type), the
object has to have external linkage (at least in C++03). Most objects
defined in namespace scope have global linkage, but const objects don't.
So you have something like:
template <char const* n>
class Toto { /* ... */ };
char const n1[] = "abc";
Toto<n1> t1; // Illegal...
extern char const n2[] = "xyz";
Toto<n2> t2; // Legal...
It's sort of a special case, but it has led me (once or twice) to use
extern in an unnamed namespace in a source file.

How to access global const variable present in one file to different file

This variable is defined in xyz.cpp
const int i = 10;
The below main() method is written in abc.cpp
void main()
{
cout<<i; //trying to access 'i' from a different .cpp file
}
You need to declare it extern in abc.cpp:
extern const int i;
EDIT: As stated in the comment below, in C++ (unlike C), to give a const variable external linkage, you need to declare it es extern also in xyz.cpp:
extern const int i = 10;
Reference: MSDN
The simplest way is to declare it in a header as const static int i=10; and include that header in all the .cpp that need that constant. This will allow it to be "inlined" by the compiler in every object file, still avoiding ODR violations.
---edit---
Actually, in C++ the static is not required, since const objects have internal linkage by default. But in C, you have to put that static (and in C++ it doesn't hurt).
Why is this better than the extern method? Because:
it's more idiomatic. In C++ you'll always write integral constants in headers as const variables (and that's the very reason why they have internal linkage by default).
it's less typing. You just have to write the const declaration once, then your constants are just a #include away.
it (usually) produces more efficient code. The definition of extern-declared variables cannot be accessed by the compiler when it is producing the current object module, so it cannot optimize it by putting its actual value as an immediate value in the produced machine code, it cannot eliminate branches that cannot be reached with that value of the constant, ... Sure, cross-module optimization ("link time code generation", "whole program optimization", ...) does exist, but at the moment compilers have more advanced optimizers than linkers.
Add the keyword extern in front of it.
Declare it in abc.cpp as:
extern const int i = 10;
const variables in C++ have an internal linkage in C++(unlike C). So to be able to use it in another file you have to explicitly declare it as having external linkage.
Put this global variable into header and #include this header in all .cpp files where you want to use it.
xyz.h:
const int i = 10;
xyz.cpp:
#include "xyz.h"
void main()
{
cout << i;
}
Or if you want to avoid using header for this purpose, you can declare it as extern const int i = 10; in xyz.cpp, but then you have to declare this variable in abc.cpp too, so you should write extern const int i; at the beginning of abc.cpp in order to use it.
The same way as using extern variables.
In the file xyz.cpp:
extern const int i = 333;
In the file abc.cpp:
extern const int i;
cout << i;