I have such pretty little code:
//example1
namespace
{
int a;
}
int a;
main()
{
a++;
return 0;
}
Of course, g++ 4.6.1 compiler can't compile it and outputs an error:
./temp.cpp: In function ‘int main()’:
./temp.cpp:10:5: error: reference to ‘a’ is ambiguous
./temp.cpp:6:5: error: candidates are: int a
./temp.cpp:2:9: error: int {anonymous}::a
It's all right!
But when I delete the reference to variable "a" within "main" function, the program is being compiled well:
//example2
namespace
{
int a;
}
int a;
main()
{
return 0;
}
1) Why does the g++ compiler allows the definition of variable "a", when in such case it disallows the references to it?
2) Is it just the g++ compiler's feature, and no other compiler is able to compile such code (example2)?
3) Does the g++ compiler have corresponding flags to interpret such code (example2) as faulty?
Thanks a lot for everyone!
The second example is valid because you can still access the global a from outside that translation unit.
The a in the anonymous namespace provides a definition for a variable that has internal linkage. The a at global namespace scope is a definition for a variable with external linkage. You can declare a extern int a; in a different translation unit and use it.
Just because you can't reference the a in the anonymous namespace from main doesn't mean the code is invalid.
The a in the anonymous namespace can still be referenced from within the anonymous namespace.
The global a can be referenced from everywhere (you'd have to use ::a in main to remove the ambiguity).
The short answer is "because there's nothing illegal about it". It's just using a in main that is wrong. If you use ::a it will give you the global one (without the namespace).
And you can use a inside the namespace itself, e.g. we could have a function:
namespace {
int a;
int work_with_a()
{
a += 2;
return a;
}
}
int a;
int main()
{
::a++;
int b = work_with_a();
cout << ::a + b;
}
Related
Here is the code example:
namespace A
{
int k;
}
void k(int,int){/*dosomething*/}
int main()
{
using namespace A;
k(1,1);//ooop!k is ambiguous!
}
What happened? I thought it should not be ambiguous since they are different types. Why is it ambiguous? With int k it is not possible to do k(1,1).
So it has nothing to do with what the name actually is?Even if a name that is not a function type will also cause ambiguity when we use k(1,1) ,which is wrong in grammar because int k is not function?
Lookup of the name k is ambiguous because there are two matching declarations visible, ::k and ::A::k .
The exact rule can be found in the C++ Standard (N4659 [basic.lookup]/1):
Name lookup associates the use of a name with a set of declarations of that name. The declarations found by name lookup shall either all declare the same entity or shall all declare functions; in the latter case, the declarations are said to form a set of overloaded functions.
Looking up an unqualified name that is used for a function call has two stages:
Unqualified lookup of the name
Argument-dependent lookup of the name.
The unqualified name lookup rules, even when looking up a name that is being used for a function call, find any declaration of that name. (The rule is NOT that it only searches for function declarations of that name). This stage finds both ::k and ::A::k regardless of whether those are functions, ints, or whatever.
The argument-dependent lookup does have a rule that only function declarations are found for that part of the lookup. But that is not relevant to this code.
The relevant behaviour of the using directive is covered by [basic.lookup.unqual]/2 (edited by me to just show the parts relevant to this question):
For the purpose of the unqualified name lookup rules, the declarations from the namespace nominated by the using-directive are considered members of that enclosing namespace.
This clarifies that using namespace A; does not actually introduce the members of A into the scope of main(); but it means that when looking up a name in the global namespace (because that is the innermost enclosing namespace of the site of the using declaration), the names from A will also be found there.
There are three ways to resolve the ambiguity:
1st:
int main() {
A::k = 5;
::k( 1, 1 );
}
2nd:
int main() {
using namespace A;
A::k = 5;
::k(1, 1);
}
3rd:
namespace A {
int k;
}
namespace B {
void k( int, int ) { /* do something */ }
}
int main() {
using namespace A or B but not both!
if A then k = 5; okay && k(1,1); error
if B then k(1, 1); okay && k = 5; error
if both again ambiguous unless A::k = 5; || B::k(1,1);
return 0;
}
Due to the nature of ambiguity it doesn't truly pay to use using namespace A. And this is why it is considered bad practice to have using namespace std; either in the global scope or directly in the main function. It is okay to use it in a function or a member function of a class/struct as long as you don't conflict with any other library.
I ran this in my IDE visual studio 2017 CE and here is the compiler error:
1>------ Build started: Project: ChemLab, Configuration: Debug Win32 ------
1>main.cpp
1>c:\...\visual studio 2017\projects\chemlab\chemlab\main.cpp(17): error C2872: 'k': ambiguous symbol
1>c:\...\visual studio 2017\projects\chemlab\chemlab\main.cpp(8): note: could be 'void k(int,int)'
1>c:\...\visual studio 2017\projects\chemlab\chemlab\main.cpp(6): note: or 'int A::k'
1>Done building project "ChemLab.vcxproj" -- FAILED.
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========
When you use the using namespace directive it will take everything that is in that namespace and make it visible to main. So now in main you have both the namespace A and the global namespace visible within main. Since you have both visible you now have 2 identifiers or symbols in the look up table named k. And when you call k(1, 1) it doesn't know which one you intended to choose.
This is no different than doing this:
main.cpp
#include <string>
class string {
public:
char* _chars;
};
int main() {
using namespace std;
string myString; // error ambiguous did you mean ::string or std::string?
return 0;
}
This might provide you with some more insight:
When the using directive is being used, don't think of the variable k and the function k as being declared in the same scope. They were previously declared in their own scope. The variable k is in ::A::k and the function void k(int,int){} is in ::k(int,int){}. In the main function when you apply the using namespace A; what happens here it takes every symbol after A:: and it kind of shifts it as if it were in the global :: scope for visibility. Now the compiler has to make a choice on the available symbols and sees I have a k and a k. Did you mean int k(){} or void k(int,int){}...
The ambiguity comes from the name. There is no way to overload a variable like you would a function/method, so there is a "clash" in the names.
In order to get the "k" that you want, you need to specify the namespace.
namespace A
{
int k;
}
void k(int, int) {/*dosomething*/ }
int main()
{
using namespace A;
::k(1, 1); // uses the global namespace
A::k = 5; // uses the namespace A
}
Or, to take the namespace out of the equation:
void k(int, int) {/*dosomething*/ }
void k(int, int, float) {}
int main()
{
int k;
// all of these are now ambiguous
k(1, 1);
k(1, 2, 0.4);
k = 5;
}
I read some answers about this topic, but I am still not sure:
In C++ a global const variable definition is automatically static. However I can access it from another cpp-file through extern:
// module.cpp
const int i = 0;
and
// main.cpp
extern const int i;
int main ()
{
if (i > 10)
return 0;
else
return 1;
}
Why is this possible (accessing an object with internal linkage from another module)? Normally I should be forced to define i as extern const int i = 0 in module.cpp, to have an explicitely global but non-static const, or?
In comparison, this is not possible:
// module.cpp
static int i = 0;
and
// main.cpp
extern int i;
int main ()
{
i = 10; // but read-only access like (i > 10) would be possible!
return 0;
}
So is the answer that: yes, you can access internal linked objects from other modules, but only for read (so always with const)?
Edit:
Sorry, but I made a mistake: in my original code I just tried an expression without effect (in both examples):
extern const int i; // or extern int i for second example
int main ()
{
i>10;
return 0;
}
I thought, that it behaves the same, as if program flow or data was dependent of this expression, but in fact it does not! The compiler seems to just cut out this effectless expression, so that the linker does not see it! So all is alright: in the first example i must be indeed defined extern const int i = 0 in module.cpp, and in the second example i cannot be accessed at all (unless in effectless expression). Compiler is VC++2010.
Edit2:
However, now I don't understand why this is possible:
// module.cpp
extern const int i = 0;
and
// main.cpp
int i = 99;
int main ()
{
bool b = i>10;
return 0;
}
i have both external linkage. But no error. When in module.cpp I define int i = 0, then error (multiple symbols). Why?
As for me it looks like a compiler bug. Constant variable i is not defined It is only declared in main.cpp. As for variable i in module.cpp then it has internal linkage and shall not be accessible outside the module.
Relative to your addition to the original post then the compiler has nothing common with this situation. It is linker that checks whether there are duplicate external symbols. I think it decided that if one variable has qualifier const and other has no it then there are two different variables. I think that it is implementation defined whether the linker will issue an error or not. Moreover it can have some options that could control the behaviour of the linker in such situations.
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
undefined reference to static member variable
What is an undefined reference/unresolved external symbol error and how do I fix it?
#include<iostream>
using namespace std;
class abc {
private:
static int a ;
public:
abc(int x) {
a = x;
}
void showData() {
cout<<"A = "<<a<<endl;
}
};
int main() {
abc a1(4);
abc a2(5);
a1.showData();
a2.showData();
return 0;
}
When I try to compile this function on Ubuntu with GCC compiler. I get the following error.
/tmp/ccCKK2YN.o: In function `main':
static1.cpp:(.text+0xb): undefined reference to `Something::s_nValue'
static1.cpp:(.text+0x14): undefined reference to `Something::s_nValue'
collect2: ld returned 1 exit status
Compilation failed.
Where as the following code runs fine
#include<iostream>
using namespace std;
class Something
{
public:
static int s_nValue;
};
int Something::s_nValue = 1;
int main()
{
Something cFirst;
cFirst.s_nValue = 2;
Something cSecond;
std::cout << cSecond.s_nValue;
return 0;
}
Is this because Static member variables needs to initialized explicitly before accessing them via objects.Why so ?
static int s_nValue; doesn't allocate any storage to store the int, it just declares it.
You allocate somewhere in memory to store the variable with:
int Something::a=0;
The declaration of a static data member in the member list of a class is not a definition. You must define the static member outside of the class declaration, in namespace scope.
See this thread.
In short, the static member needs to be initialized somewhere in a .cpp file so that the compiler allocates space for it. The declaration would look like this:
int abc::a = 0;
That happens because since static members are shared between all instances of a class, they need to be declared in one single place.
If you define the static variable inside the class declaration then each include to that file would have a definition to that variable (which is against to the static meaning).
Because of that you have to define the static members in the .cpp.
#include<iostream>
#include<stdlib.h>
#include<string.h>
using namespace std;
class div
{
int x,y;
public:
class dividebyzero
{
};
class noerror1
{
};
div(){};
div(int a,int b)
{
x=a;
y=b;
}
void error1()
{
if(y==0)
throw dividebyzero();
else
throw noerror1();
}
int divide()
{
return (x/y);
}
};
class naming
{
char name[32];
public:
class nullexception
{
};
class noerror2
{
};
naming(char a[32])
{
strcpy(name,a);
}
void error2()
{
if(strcmp(name,"")==0)
throw nullexception();
else
throw noerror2();
}
void print()
{
cout<<"Name-----"<<name<<endl;
}
};
int main()
{
div d(12,0);
try
{
d.error1();
}
catch(div::dividebyzero)
{
cout<<"\nDivision by Zero-------Not Possible\n";
}
catch(div::noerror1)
{
cout<<"\nResult="<<d.divide()<<endl;
}
naming s("Pankaj");
try
{
s.error2();
}
catch(naming::nullexception)
{
cout<<"\nNull Value in name\n";
}
catch(naming::noerror2)
{
s.print();
}
return 0;
}
On compiling this program I am getting following error
pllab55.cpp: In function ‘int main()’:
pllab55.cpp:61:6: error: expected ‘;’ before ‘d’
pllab55.cpp:64:3: error: ‘d’ was not declared in this scope
pllab55.cpp:72:22: error: ‘d’ was not declared in this scope
pllab55.cpp:74:20: warning: deprecated conversion from string constant to ‘char*’ [-Wwrite-strings]
Before declaring the class naming everything was running fine.It is after declaration of naming these error started to occur. I am new to C++. Please explain me in details. Thanks in advance.
There is already an std::div in the standard namespace and since you use a using namespace directive instead of declaration it imports all the symbols in std namespace to your current scope. So perhaps renaming the div class shall do the trick for you.
I tried renaming it and it does work indeed.
So either rename your class or wrap it in your own namespace so it does not conflict with std::div
Your class div shares the same name as std::div. When you do #using namespace std, the result is that each class in the std namespace is imported into your current scope, meaning that std::div is now essentially called div. If you see, that means you now have two classes called div in the same scope, your own and the std class.
By the way, you should avoid the using namespace syntax and rather use the full qualifier of the class (e.g. std::cout).
Your div class is conflicting with std::div so either rename yours or put put your div class in a different namespace.
namespace me {
struct div{};
}
me::div d;
I gave (a slight variant of) your code a try in gcc and I got the following error:
/usr/include/stdlib.h:780: error: too few arguments to function 'div_t div(int, int)'
You're trying to override a name from a standard library and experience the conflict of a class and a function having the same name, I'm afraid.
as a general rule of thumb, if you encounter such issues, try to reduce your code as much as possible. For instance, I reduced it down to
#include<stdlib.h>
class div {
public:
div (int a, int b) { }
};
int
main () {
div d (12, 0);
return 0;
}
which still shows your error (at least the first one - the others are followup errors).
This lets you also reduce possible assumptions about the reason for the error - as you see, your new class "naming" does not have to do anything with the error you see.
When I now additionally remove the include, the error does not show up anymore, which lets me suspect some naming clash with some symbol from stdlib.h. After renaming the class "div" to something else (like "CDiv"), it works.
I'm learning C++ now. What are the complete legal entities that can be put in a namespace?
Legal entities here means valid members of a namespace
Oh, this is a real question. I'm coming from .net and I have the .net mindset.
Any code can be put inside namespace.
However main() function must be at global namespace. It cannot be put inside user-defined namespace.
namespace userns
{
int main()
{
return 0;
}
}
This program wouldn't compile link : http://www.ideone.com/k6SPc
Its because userns::main() will not be considered entry-point of the program; it became just like any other user function, not the standard main(). To compile it successfull, you've to add main() at global namespace:
namespace userns
{
int main()
{
return 0;
}
}
int main()
{
return 0;
}
This will compile link now : http://www.ideone.com/76Ynu
Anything can be put in a namespace (which is legal for C++, of course).
Actually, everything is in some namespace - the global namespace, if not specified.
Everything can be put in namespace except few "entities", which will not compile.
(1) Globally overloaded operator new and operator delete
namespace N
{
void* operator new (size_t size) // error
{ ... }
}
(2) Definition of the constructs which are declared in outer scope of the namespace; for example you have a class A declared globally then you cannot define its method inside your namespace N. In the same way, if you have method declared in a namespace N then you cannot put its definition inside namespace N::Nested (i.e. Nested is a namespace inside N).
//file
struct A {
void foo ();
static int i;
};
namespace N
{
int A::i = 0; // error
void A::foo() // error
{}
}
Demo: this is not allowed.
I remember at least these 2 restrictions from my experience. Don't know about specs.