The following C++ test code does not link (gcc 4.9.2, binutils 2.25). The error is In function 'main': undefined reference to 'X::test'
.
01: #include <string>
02: #include <iostream>
03:
04: namespace X
05: {
06: extern std::string test;
07: };
08:
09: using namespace X;
10: std::string test = "Test";
11:
12: int main()
13: {
14: std::cout << X::test << std::endl;
15: }
Because of line 09, I was expecting line 10 to define the X::test
variable declared on line 06. I believe that instead an unrelated test
variable is declared and defined in the global namespace, hence the linking error.
Question: Could anyone please explain why my expectation was incorrect, and what is happening exactly?
Not the answer:
std::string X::test = "Test";
.The biggest advantage of using namespace is that the class names which are declared in one namespace will not clash with the same class names declared in another namespace. It is also referred as named group of classes having common features.
The statement using namespace std is generally considered bad practice. The alternative to this statement is to specify the namespace to which the identifier belongs using the scope operator(::) each time we declare a type.
Namespace in C++ is the declarative part where the scope of identifiers like functions, the name of types, classes, variables, etc., are declared. The code generally has multiple libraries, and the namespace helps in avoiding the ambiguity that may occur when two identifiers have the same name.
In C++, a namespace is a collection of related names or identifiers (functions, class, variables) which helps to separate these identifiers from similar identifiers in other namespaces or the global namespace. The identifiers of the C++ standard library are defined in a namespace called std .
The directive using namespace X;
makes names from namespace X
visible inside the namespace containing the directive. That is, when looking up a name n
in that scope, X::n
can be found. However, it will only be looked for if the compiler needs to look for it.
In your example, this declaration:
std::string test = "Test";
inside the global namespace makes perfect sense as-is. The name test
is simply introduced, as with any other declaration. No need to look it up anywhere.
This would be an entirely different kettle of fish:
namespace X
{
struct C
{
static std::string test;
};
}
using namespace X;
std::string C::test = "Test";
In this code, the compiler needs to know what C
is to make sense of the definition of C::test
. It therefore does a name lookup of C
, which indeed finds X::C
thanks to the using
directive.
using namespace
means you use definitions from the namespace you specified, but it doesn't mean that everything that you define is being defined in a namespace you use.
Logic of this behavior is pretty simple. Let's say we have the following example:
namespace X
{
extern string test;
};
namespace Y
{
extern string test;
};
using namespace X;
using namespace Y;
string test = "value";
Following your example logic, compiler just would not know in which namespace it should define test
, so you would have to declare the namespace explicitly. In a real life it is defined in a global namespace.
In your specific case you define the test
variable outside of the X
namespace where it is declared as extern
. Linker looks for definition of the X::test
but doesn't find and as a result you see this error.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With