I have the following two sample c++ files:
File: foo.cc
namespace test_ns {
int x = 100;
}
File: bar.cc
using namespace test_ns;
extern int x;
int main()
{
x = 200;
return 0;
}
I must be doing something really silly as I am getting the following compiler error:
bar.cc:2:17: error: 'test_ns' is not a namespace-name
bar.cc:2:24: error: expected namespace-name before ';' token
However, my main question (after I resolve the namespace error), with the code as is, should I be able to use "x" in bar.cc, or do I need to use additional qualifiers.
Sorry to bother with such a simple issue, but I am pretty stumped with such a simple program.
Thank you,
Ahmed.
Just like every other name in C++, a namespace name must be declared before it can be accessed. When compiling bar.cc, the compiler doesn't know test_ns is a namespace name - you haven't provided a declaration for it.
Namespaces and using namespace aren't magical tricks that let you get around the necessity to declare anything you want to use. To make this work, create a header file:
foo.hh
namespace test_ns {
extern int x;
}
Then #include "foo.hh" in bar.cc, and remove extern int x; from bar.cc. That will make these two translation units form a valid program. And after you do that, referring to x in bar.cc will indeed refer to test_ns::x (thanks to the using directive).
As a side note, if you don't remove the extern int x; from bar.cc (after you include the header file), it will declare a new global variable ::x and not refer to test_nest::x. using namespace in a source file allows you to define class members without referring to the class's namespace, but namespace-scope entities (variables and functions) always have to be defined inside the namespace or using a qualified name.
They are in different compilation units. You need to declare the namespace in a common header; which you can do using:
namespace test_ns {}
namespace is defined in a different file. It needs to be defined in a header file which should be included in bar.cc .
Related
1) I know a non-const variable is external linkage by default (it's like it's been declared as external more or less) but i don't understand why can't i define a global variable such as int glbl_a in header
//test.h
#ifndef TEST_H
#define TEST_H
int glbl_a=0; //wrong -> "multiple definition of `glbl_a`"
static int st_glbl_a=1; //ok to initialize it in header!
extern int ext_glbl_a; //ok to declare it and define it in test.cpp
#endif
//test.cpp
#include "test.h"
using namespace std;
//st_glbl_a=22; i could use st_glbl_a but it wouldn't affect st_glbl_a in main cause of 'static'
int ext_glbl_a=2; //definition of external gloabal non-const variable
//main.cpp
#include <iostream>
#include "test.h"
using namespace std;
extern int glbl_a; //declaration of glbl_a external
int main(){
cout<<glbl_a;
}
the working version for this program is the one in which I define int glbl_a=0; in test.cpp only and declare extern int glbl_a; in main before using it in output (definition in test.h is just commented, that is there's nothing about glbl_a).
2)the working version doesn't work anymore if I group all definitions/declaretions into a namespace spread onto test.cpp and test.h (MyNamespace) cause of int glbl_a in test.cpp:
//test.h
#ifndef TEST_H
#define TEST_H
namespace MyNamespace{
//extern int glbl_a;
}
#endif
//test.cpp
#include "test.h"
using namespace std;
namespace MyNamespace{
int glbl_a=0;
}
//main.cpp
#include <iostream>
#include "test.h"
using namespace std;
int main(){
cout<<MyNamespace::glbl_a; //wrong -> "'glbl_a' is not a member of 'MyNaspace'"
}
it would work only if I de-comment declaration in test.h, but why?
Problem 1
Including a header effectively pastes the included file into the including file, producing one large file that is then compiled (and, typically, promptly deleted). This means that every including file now has its very own glbl_a. The compiler is happy, but when the linker attempts to put everything together, it finds many equally valid pretenders to the name glbl_a. The linker hates this and doesn't even try to figure out what you're trying to do. It simply spits out an error message and asks that you fix the problem.
Problem 2
test.cpp and main.cpp are different translation units. They compile to produce different, completely independent objects. Neither can see what's in the other, so the fact that MyNamespace::glbl_a exists in test.cpp is lost on main.cpp. When main.cpp is compiled, the compiler builds a list of identifiers declared in the file constructed from main.cpp and all of its included headers. MyNamespace::glbl_ais never declared as of when it is first used (or after for that matter) so the compiler spits out an error message.
Uncommenting the declaration in test.h means the compiler will find MyNamespace::glbl_a in main.cpp and will allow it's use. Since MyNamespace::glbl_a is defined in test.cpp the linker can find one-and-only-one MyNamespace::glbl_a and can successfully link.
extern does not allocate storage. Instead it is a promise to the compiler that the variable being declared will be fully defined and allocated somewhere else, maybe later in the file or in another file. The variable exists, somewhere, and compilation can continue. The linker will call you out as a liar if it cannot find a definition.
More details here: How does the compilation/linking process work?
More on extern: When to use extern in C++ and Storage class specifiers
headers will be included by other files (more than one) thus if you define in header, it will be in each translation unit thus lead to "multiple definition"
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];
...
}
I am still kind of new to many areas of c++ and one is general .cpp and .h file organization.
I am creating a namespace with some structs and functions. I would like to declare the namespace in a .h file similar to this
//objectname.h
namespace ObjectName
{
Object Function(arguments);
}
declarations in function.h
//function.h
//includes declarations used in the function definition as well
//as possibly a redundant function declaration.
Object Function(arguments);
then the definition in function.cpp
//function.cpp
#include "Function.h"
Object Function(arguments)
{
....
}
So that you can see abstractly the namespace in objectname.h, function particular declarations in function.h and function definition in function.cpp. As always any suggestions are greatly appreciated. (also windows based c++)
This is fine
//objectname.h
namespace ObjectName
{
Object Function(arguments);
}
You don't need function.h at all. If you want to split the namespace into several files, you would do it like:
//function.h
//includes declarations used in the function definition as well
//as possibly a redundant function declaration.
namespace ObjectName
{
Object Function(arguments);
}
In other words you need to wrap the declaration in the namespace again. (This is an advance topic. I wouldn't do it.)
Function.cpp just needs to say which function it is defining:
//function.cpp
#include "ObjectName.h"
Object ObjectName::Function(arguments)
{
....
}
Note that the statement to use a header file is #include, not using
That's not how it works: your function.h defines another Function in the global namespace. Having two functions with the same name is exactly what namespaces are for - a library write doesn't need to worry if there's already a Function in any other library.
And as your .cpp defines only one of the two Functions, the other one is undefined and will give a link error when called.
Note that you do not need to "define" a namespace all at once. Take for instance namespace std, whose contents are found in e.g. <vector>, <list> and <iostream>. This is possible because unlike a class, a namespace can be reopened. namespace N { int x; } namespace N { int y; } is valid.
I want to use extern keyword for user defined types. This means I've declared object in one file and defined it in other file. I've read that extern keyword is used to declare the variable without defining it. extern keyword is useful when program is split into multiple source files and global variable needs to be used by each of them. Please correct me If I am wrong somewhere.
Here is the programs I've written but unfortunately I am doing something wrong or missing something so I am getting compiler errors.
Prog1.cpp
#include <iostream>
using std::cout;
class test
{
public:
void fun();
};
void test::fun()
{
cout<<"fun() in test\n";
}
test t;
Prog2.cpp
#include <iostream>
using std::cout;
extern test t;
int main()
{
t.fun();
}
Now when I compile these 2 using
g++ -o prog1.cpp prog2.cpp
compiler gives me following errors in prog2.cpp
error: 'test' does not name a type
error: 't' was not declared in this scope
Please help me to know what I've done wrong here.
extern tells the compiler that the definition of t is somewhere else, but the compiler still needs the defintiion of test, as you're using t.fun() to compile Prog2.cpp.
So the solution is, write test.h where you define the class, and then define test t in Prog2.cpp as usual. Include test.h in your Prog2.cpp so that it may know the definition of test. Then build it.
test.h:
#include <iostream>
using std::cout;
class test //definition of test
{
public:
void fun()
{
cout<<"fun() in test\n";
}
};
Prog1.cpp:
#include "test.h"
test t; //definition of t
Prog2.cpp:
#include <iostream>
#include "test.h"
using std::cout;
extern test t; //the definition of t is somewhere else (in some .o)
//and the definition of test is in test.h
int main()
{
t.fun();
}
Now your code should compile and link.
Note that the definition of t is needed by the linker at link-time, so it will search for it in other .o files, but the definition of test is needed by the compiler, at compile-time.
Now it should be obvious that you can put the extern test t; in the header itself so that you dont have to write it in every .cpp file where you want to use the object defined in Prog1.cpp file (which is turned into Prog1.o by the compiler).
Put the extern keyword in the header, not the cpp file. It is the job of the header to tell the compiler there is an externally defined object somewhere.
For example:
program.h (mostly declarations)
struct UserDefinedType
{
void do_stuff();
};
// declare your global object in the header
// so that the compiler knows its name when
// compiling sources that can not otherwise see
// the object
extern UserDefinedType global_udt;
program.cpp (mostly definitions)
#include "program.h"
// define the member functions here
void UserDefinedType::do_stuff()
{
}
// define the global object here
UserDefinedType global_udt;
main.cpp (use the definitions that have been declared in the header)
#include "program.h" // tells the compiler about global_udt
int main()
{
// call the global object that is defined
// in a different source file (program.cpp)
global_udt.do_stuff();
}
NOTE: If we didn't declare the object global_udt in the header file then main.cpp would not know of its existence and the compiler would complain if we tried to use it.
So the header needs to only declare the object and not define it hence the extern keyword is needed.
Please note that a variable declared outside the class scope is a variable with external linkage(if not explicitly used the static keyword) or with internal linkage(if the static keyword is put in the left of the variable type), extern is necessary if you want to use it in multiple files.
Suppose this file is called MyVariable.h
int myNumber = 0; // Initialization of the variable myNumber, external linkage
static int myStaticNumber; // Initialization of the variable myStaticNumber, internal linkage(only the file in which it's declared)
And this file is OtherFile.cpp
extern int myNumber; // Not a initialization because it's already initialized in another file, works fine
extern int myStaticNumber; // ERROR, this variable has internal linkage!!
You may wonder why myStaticNumber was initialized and not just declared, that occurs because static variables are initialized to their default values by default.
Can someone please explain to me the life cycle of a variable from a namespace? Let's say I have the following files:
file.h:
// ...
namespace variables{
int x, y;
}
file.cpp:
#include "file.h"
using namespace variables;
int main(){
...
}
What are the scopes of x and y? I ask because, in a book I was reading (C++ Primer Plus), the author recommends using namespaces inside functions, and so I thought that they are defined at the point of the using command. However, when I do this:
B.h:
class B{
// class stuff
};
namespace variables{
int x, y;
}
and then in main.cpp (main program) and B.cpp (class implementation) I add the #include "B.h" line, I get an error that I have multiple definitions of variables::x and variables::y, even though there is no using in any file. What's the deal? Am I mixing up two different concepts?
If you directly declare variables in a namespace just like you did, they will simply exist as global variables.
Thus, the rules that apply for normal global variables also apply for those ones : they will exist for as long as the program run, and you should not define them in a header file.
include.h
namespace Variables
{
extern int x;
extern int y;
}
file.cpp
namespace Variables
{
int x;
int y;
}
Writing using namespace Variables will simply allow you to access those variables by their name x and y, without having to prefix them with Variables::
Namespace has no influence on variable's lifespan, so:
namespace variables{
int x, y;
}
#include "file.h"
using namespace variables;
int main(){
...
}
What are the scopes of x and y?
These variables are global, so their life time equals to life time of the entire application.
Remember, that using namespace is simply a shortcut to writing NamespaceName:: in front of elements from this namespace.
I add the #include "B.h" line, I get an error that I have multiple definitions of variables::x and variables::y, even though there is no using in any file. What's the deal? Am I mixing up two different concepts?
Your variables are declared even if you do not explicitly import the namespace. The keyword using import namespaces or specific names within the current scope so that you don't have to prepend X:: to access a defined element.
The life span of a variable is not affected by namespaces.