I thought I understood name lookup very well (after having watched several videos about it and read a lot) but I just hit this case:
#include <iostream>
namespace test{
struct Id
{};
void do_something( const Id& ){ std::cout << "Hello, World!" << std::endl; }
class Test
{
public:
void do_something() { std::cout << "WTF!" << std::endl; }
void run()
{
Id id;
do_something( id ); // doesn't compile
}
};
}
int main()
{
test::Test my_test;
my_test.run();
}
The pointed line don't compile (on GCC4.8 and VC11U2) because it tries to use the member function test::Test::do_something()
instead of the namespace-scoped test::do_something( const Id& )
which seem like the only possible candidate.
Apparently the member function name hides the namespace-scoped names which is surprising to me because I remember using almost similar code in other context without this problem spawning (but the conditions might have be very different in the end).
My question is: are these compilers confirming to the standard?
(Name lookup is very hard to understand by reading the standard document unfortunately, so I need expert confirmations)
An anonymous namespace makes the enclosed variables, functions, classes, etc. available only inside that file. In your example it's a way to avoid global variables. There is no runtime or compile time performance difference.
The reason is that using directive eliminate the protection of that particular namespace, and the effect last until the end of current compilation unit.
Namespaces are basically just to organize your code. using namespace std; is used to inform the compiler to look for the io functions in this standard library. If it is not used, the compilation will flag an error that cin/cout is undefined. It is compiler dependent.
The problem with putting using namespace in the header files of your classes is that it forces anyone who wants to use your classes (by including your header files) to also be 'using' (i.e. seeing everything in) those other namespaces. However, you may feel free to put a using statement in your (private) *. cpp files.
My question is: are these compilers confirming to the standard?
Yes. Before overload resolution decides which functions are viable candidates (which includes checking the number of parameters) the compiler first has to do name lookup, to find all candidates, viable and non-viable. In your example name lookup stops after finding the member do_something()
so overload resolution never gets a chance to decide whether the namespace-scope one is viable.
3.4.1 [basic.lookup.unqual]/1: "In all the cases listed in 3.4.1, the scopes are searched for a declaration in the order listed in each of the respective categories; name lookup ends as soon as a declaration is found for the name."
3.4.1 [basic.lookup.unqual] paragraph 8 lists the contexts searched for the name and even has an example that answers your question exactly. The scope of Test
is searched before the enclosing namespace, and as paragraph 1 says "name lookup ends as soon as a declaration is found for the name".
The further a language goes out of its way to find a valid interpretation for a construct, the more likely it is that a typo or other such mistake will result in the compiler finding a meaning which is valid but wrong. The compiler is assuming that if foo
is defined within some scope, and code within that scope uses foo
, the programmer intends for the code to use the foo
that is defined within the scope. If the programmer tries to do something with foo
that is not permitted by its inner scope definition, odds are very good that one of the following is true:
foo
can't support it, and will thus have to find some other operation or sequence of operations the inner foo
can support. Again, a compiler can't be expected to generate good code unless the programmer indicates how to use foo
properly.Only if the programmer's intention was #3 could a compiler possibly generate code which would behave as intended. It's far more likely, however, that a programmer really intended #1 or #2. If the compiler refuses to compile code even when assuming #3 would produce valid code, then any of the above mistakes will be found and can thus be corrected. By contrast, if compiler assumed #3 whenever it could, then if the programmer really intended #1 or #2 problems would not manifest themselves until the code was run and behaved contrary to design.
BTW, if I had my druthers, I would apply this principle to case-sensitivity in .NET languages, forbidding not only the writing of any identifier in a fashion inconsistent with the definition (as is done by C# but not vb.net), but the use of any identifier which differs only in upper/lower-casing from one in an inner scope. For example:
class foo
{
int x;
void bar()
{
int X=2;
x=4; // ****
return X;
}
}
Given the above code, C# would guess that the line with the asterisks was intended to write the field; given similar code, vb.net would assume it was intended to write the local variable. Personally, I dislike both assumptions; the principle of "say exactly what you mean" would suggest to me that a compiler should require the programmer to either say this.x=4;
or X=4;
, neither of which could possibly be read as having the wrong meaning.
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