According to unqualified lookup in cppreference.com:
For a name used in the definition of a function, either in its body or as part of default argument, where the function is a member of user-declared or global namespace, the block in which the name is used is searched before the use of the name, then the enclosing block is searched before the start of that block, etc, until reaching the block that is the function body. Then the namespace in which the function is declared is searched until the definition (not necessarily the declaration) of the function that uses the name, then the enclosing namespaces, etc.
So I thought function names defined in global namespace scope shall be found simply through unquailifed lookup. However, the following piece of code fails to compile:
#include <iterator>
#include <iostream>
namespace AA{
class AAA{};
};
using namespace AA;
int begin(AAA ){
return 3;
}
int main(){
using std::begin; // to add std::begin in the name candidate set
auto x = AAA();
return begin(x); // compile error, ::begin cannot be found
}
Both GCC(6.1.1) and Clang(3.8.0) reports the same error.
And, either I remove the using std::begin statement or move class AAA to namespace AA, the above program compiles successfully. So I think once my begin is found through name lookup, it will be chosen through overload resolution. Therefore the question is: why my begin function declared and defined in global scope is simply not found in the code case above?
Note that unqualified name lookup will stop if the name is found (at some scope), then the further scopes won't be searched. For your sample code, the name begin will be found at the function scope of main(), (which refers to std::begin), then name lookup stops, so the name in global scope won't be examined.
..., name lookup examines the scopes as described below, until it finds at least one declaration of any kind, at which time the lookup stops and no further scopes are examined.
From the quotation you posted (emphasis added by me):
etc, until reaching the block that is the function body. (the name lookup will stop here, i.e. in the block of main() function body)
Then the namespace ... (The further namespace won't be searched.)
Related
Question on namespace qualification: Why isn't the namespace of the function inferred below?
namespace X {
void func(int) {}
struct Z{
void func(){
//func(int{}); does not compile
X::func(int{}); // this works
}
};
}
int main() {
X::Z z;
z.func();
}
This specific part of C++ can be generally called "unqualified name lookup". This term describes taking a single identifier in a C++ program and then determining which actual type, or object, or function, or class, it is referencing.
For example, there can be many things called rosebud in a C++ program, so
rosebud();
This can reference a class method of this name, and this calls it. Or this could be an object with an overloaded () operator, which invokes it. There could also be something called rosebud() in a different namespace. Unqualified name lookup specifies which one of these this particular rosebud references.
struct Z{
void func(){
Here we're in a method of class Z. Unqualified name lookup first looks for identifiers that are members of this class. Only if it's not found then does unqualified name lookup looks in the global namespace, to see if something is there.
func(int{}); // does not compile
Well, there happens to be a method with the name func in this class, so this func's unqualified name lookup resolves to this method. This fails, because that func method takes no parameters.
Unqualified name lookup considers where exactly the unqualified identifier occurs. When it occurs in a class, unqualified name lookup searches the class's members, first.
Even though there's also a func function in the global scope, unqualified lookup finds the class method, and that's it (quoting from the cited link):
[unqualified] name lookup examines the scopes as described below,
until it finds at least one declaration of any kind, at which time the
lookup stops and no further scopes are examined.
End of the road. The fact that there's also a func in the global namespace is immaterial. For unqualified name lookup, once "something" is found, it better work, or else.
These are just one of the rules of unqualified name lookup.
X::func(int{}); // this works
Well, yes. This explicitly references func in the X namespace. This symbol is (partially) qualified with an explicit namespace reference.
I'm getting a "too few arguments in function call" while trying to call a function from another namespace that happens to have the same name with the function it's being called from. Here, you can see what I mean:
namespace doa::texture {
using namespace internal::texture;
Texture* const CreateTexture(const std::string& name, const std::string& pathToTextureImage) {
//below should call internal::texture::CreateTexture, not doa::texture::CreateTexture
Texture* texture{ CreateTexture(pathToTextureImage) };
... //implementation detail
}
}
namespace internal::texture {
Texture* const CreateTexture(const std::string& pathToTextureImage) { ... }
}
I can easily fix the error by slapping an internal::texture in front of the function call but since I'm using the using namespace internal::texture directive, the compiler should be able to pick it up.
I can also move the CreateTexture function from the namespace internal::texture to doa::texture. But I would like to avoid that.
How can I fix this without moving the function or putting internal::texture in front of the call, and why this thing happens in the first place? This is simply a case of function overloading, why do namespaces cause such a thing to happen? Thank you.
P.S. The functions are defined in a separate file. like this:
//irrelevant implementation details are left out
namespace doa::texture {
Texture* const CreateTexture(const std::string& name, const std::string& pathToTextureImage);
}
namespace internal::texture {
Texture* const CreateTexture(const std::string& pathToTextureImage);
}
I'm going to try to put a few pieces of the C++17 standard (draft) together, and hope I'm not misinterpretting it :)
From the unqualified name lookup:
1 In all the cases listed in 6.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. If no declaration is found, the program is ill-formed.
2 The declarations from the namespace nominated by a using-directive become visible in a namespace enclosing the using-directive; see 10.3.4. For the purpose of the unqualified name lookup rules described in 6.4.1, the declarations from the namespace nominated by the using-directive are considered members of that enclosing namespace.
From using directive
2 A using-directive specifies that the names in the nominated namespace can be used in the scope in which the using-directive appears after the using-directive. During unqualified name lookup (6.4.1), the names appear as if they were declared in the nearest enclosing namespace which contains both the using-directive and the nominated namespace. [Note: In this context, “contains” means “contains directly or indirectly”. —end note]
From Name Hiding
1 A name can be hidden by an explicit declaration of that same name in a nested declarative region or derived class (13.2).
Specifically, with this last part, I believe it means that the CreateTexture function in doa::texture hides the CreateTexture in internal::texture even though it is within a different namespace. Basically, the compiler sees CreateTexture in the doa::texture namespace, then stops looking, and hence ignored the one from internal::texture
Here is a similar question, but in this question it works, however, it fails in the following circumstance, why?
namespace A
{
int k;
}
namespace B
{
class test{};
void k(const test&){/*do something*/}
}
int main()
{
using namespace A;
k(B::test());//compile error
}
Error message is: "'A::k' cannot be used as a function" (gcc 6.3.0)
That is to say, the compiler does not try to do ADL and never find the void k(const test&) in namespace B
However, I think the ADL should work in such situation because the code above does not belong to the following circumstance:
quoted from cppref
First, the argument-dependent lookup is not considered if the lookup set produced by usual unqualified lookup contains any of the following:
1) a declaration of a class member
2) a declaration of a function at block scope (that's not a using-declaration)
3) any declaration that is not a function or a function template (e.g. a function object or another variable whose name conflicts with the name of the function that's being looked up)
To be more precise, here the using namespace A does not introduce any declaration:
quoted from cppref
Using-directive does not add any names to the declarative region in which it appears (unlike the using-declaration), and thus does not prevent identical names from being declared.
The name lookup for a function call has two parts:
normal unqualified lookup
ADL
According to N4659 [basic.lookup.argdep]/3, the normal unqualified lookup happens first; and then ADL stage does not go ahead if the normal unqualified lookup found:
a declaration of a class member, or
a block-scope function declaration that is not a using-declaration, or
a declaration that is neither a function nor a function template.
In your code the normal unqualified lookup does find A::k as discussed in your previous question. So ADL does not happen for this code.
A using-directive specifies that the names in the nominated namespace can be used in the scope in which the using-directive appears after the using-directive. During unqualified name lookup (6.4.1), the names appear as if they were declared in the nearest enclosing namespace which contains both the using-directive and the nominated namespace.
So, unqualified name lookup will find A::k, that is the reason for the error.
Here is the code example:
#include<iostream>
using namespace std;
namespace B
{
int ohoh=2;
}
namespace A
{
int ohoh=666;
namespace C
{
//using B::ohoh;(as if declared by using directive) //why does the lookup not stops here?
int foo()
{
using namespace B;
cout<<ohoh<<endl;
}
}
}
int main()
{
A::C::foo();
}
The output is 666 but not 2. Why?
Quoted from cppref
For an unqualified name, that is a name that does not appear to the right of a scope resolution operator ::, name lookup examines the scopes as described below, until it finds at least one declaration of any kind, at which time the lookup stops and no further scopes are examined. (Note: lookup from some contexts skips some declarations, for example, lookup of the name used to the left of :: ignores function, variable, and enumerator declarations, lookup of a name used as a base class specifier ignores all non-type declarations)
For the purpose of unqualified name lookup, all declarations from a namespace nominated by a using directive appear as if declared in the nearest enclosing namespace which contains, directly or indirectly, both the using-directive and the nominated namespace.
From the quoted paragraph above ,the name lookup should stop at nearest namespace C ,Where I've commented in the code.Why does it does not stop and find A::ohoh ?
By the way,I think I should use the using directive as little as possible.
For the purpose of unqualified name lookup, all declarations from a namespace nominated by a using directive as if declared in the nearest enclosing namespace which contains [...] both the using-directive and the nominated namespace.
In this case, the nearest namespace that contains both B and the using-directive is the global namespace. Therefore, all names from B appear inside A::C::foo as if they were declared in the global namespace. When searching for the name ohoh, A is searched before the global namespace, so A::ohoh is the first declaration found and name lookup stops there.
I don't understand why the following code gives error:
namespace A
{
void f(double x){cout<<"A::f(double)\n";}
void f(string s){cout<<"A::f(string)\n";}
namespace B
{
using namespace A;
void f(int x){cout<<"B::f\n";}
void call()
{
f(10); // calls B::f, expected
f(10.5); // calls B::f, why??
string s="Hi";
f(s); // error, why??
}
}
}
My understanding was to search a name, compiler starts from current scope and continuously search enclosing scope and then global scope until it finds correct (correct means signature match or convertible in case of method) one, or gives error if none is present. So at first I tried without using namespace A in B. Then the first two call invoked B::f as expected, but f(s) was giving error. I thought names in enclosing scope are by default visible to inner scope, but clearly I was wrong. Then I place using namespace A and thought f(10.5) will call A::f for better type matching, and the problem with f(s) will be solved, but this is not the case (my understanding was using keyword bring everything to current scope from the scope which is being used). Can someone help me to understand how name lookup is applied here, thanks in advance.
Note
I know how to make it work. I wanted to know why this is so? what C++ standard says about this in easy to understand language. Why my understanding is wrong?
Since, you are not calling A::f(), these will happen:
f(10.5); // cast to int
string s="Hi";
f(s); //I do not know any B::f(), with string argument.
To be more exact, in the first line of the code I pasted,
the compiler will try to call f(int a). You pass 10.5 and the function waits for an integer. However, 10.5 can be casted to an int, by cutting its decimal digits. This function is the one of namespace B.
[EDIT]
The default namespace is the one you have your functions inside. In order to not the use the default, you have to specify it yourself, be the :: operator.
If you remove the f() inside the namespace B, then the compiler will go to the namespace A, which is the 'outer' namespace.
Maybe this analogy with the scope of the variables can help.
int main() {
int a = 10;
{
int a = 5;
std::cout << a << std::endl;
}
return 0;
}
The output is 5. When it's time to print a, the compiler will go and find the last declared a, except otherwise told by us.
This is what is known as name hiding:
A name can be hidden by an explicit declaration of that same name in a nested declarative region or derived class (10.2).
The declaration of B::f is hiding both overloads of A::f despite the using namespace declaration. The technical reason for which it wasn't working was because of the way unqualified lookup works. The compiler first searches the most local namespace for the symbol, and works its way up until it finds it. Implicit conversions are allowed which was why B::f was consistently being called and why the overload for std::string could not be chosen. To fix this, you can add the outer namespace function in explicitly using a using declaration:
using A::f;
void f(int) { ... }
void call()
{
// ...
}
Here is a demo.
That to understand the compiler behaviour it is important to reference to the following quote from the C++ Standard
2 A using-directive specifies that the names in the nominated
namespace can be used in the scope in which the using-directive
appears after the using-directive. During unqualified name lookup
(3.4.1), the names appear as if they were declared in the nearest
enclosing namespace which contains both the using-directive and the
nominated namespace. [ Note: In this context, “contains” means
“contains directly or indirectly”. —end note ]
In your example "the nearest enclosing namespace which contains both the using-directive and the
nominated namespace." is namespace A. That is functions
void f(double x){cout<<"A::f(double)\n";}
void f(string s){cout<<"A::f(string)\n";}
are not members of namespace B for the purpose of the unqualified lookup.
Accotding to other quote from the C++ Standard
1 A name can be hidden by an explicit declaration of that same name in
a nested declarative region or derived class (10.2).
these function declarations are hidden by the explicit declaration of f in namespace B. So the compiler found name f in namespace B and it stopped the further search of the name.
You are running into something called implicit conversion. Check out this page, or another one.
As pointed out in other answer, only the current scope is explored by the compiler, and he tries to convert the given argument to the one expected, and fails if he can't.