Why is the ADL not working when `using directive` is used? - c++

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.

Related

Inferring namespace of freestanding function

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.

Why does the name lookup does not stop when it finds the entity implicitly declared by using directive?

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.

Function names in global namepsace scope cannot be found

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.)

Friend lookup exception from template-id?

Consider the following clause in [namespace.memdef]/3:
If the name in a friend declaration is neither
qualified nor a template-id and the declaration is a function or an elaborated-type-specifier, the lookup to determine whether the entity has been previously declared shall not consider any scopes outside the innermost
enclosing namespace.
Is there a reason for the exception for template-id along with the qualified name? For that matter, is there a reason for the lookup of an unqualified name that isn't a template-id to be restricted to the innermost enclosing namespace? Is there a specific problem or use-case that this clause solves?
Why doesn't the restriction apply to qualified names and template-ids?
Qualified names and template-ids cannot introduce new members into the enclosing namespace, this is what the note in [namespace.memdef]p3 tries to say:
[ Note: The other forms of friend declarations cannot declare a new
member of the innermost enclosing namespace and thus follow the usual
lookup rules. — end note ]
Therefore, no such restriction is necessary for qualified names and template-ids.
Note that template-ids lack the declaration of the template-parameters, and qualified-ids could introduce names into distant, unrelated namespaces.
Why is there a restriction at all?
This part of the answer is still incomplete, but represents the current state of "research". Feel free to contribute.
The restriction has (probably?) been introduced due to N0783 - Namespace Issues and Proposed Resolutions which "attempts to clarify a number of namespace issues that are currently either undefined or incompletely specified".
This paper from 1995 contains two enlightening discussions of issues related to declarations of entities introduced via friend-declarations. Bear in mind that the name lookup rules back then were different:
Argument-dependent lookup had not yet been introduced(*)
Names introduced via friend-declarations are not found via pure unqualified lookup (no ADL) according to current rules, see [namespace.memdef]p3 and CWG 1477. The examples from N0878 suggest that those names could be found via pure unqualified lookup at that time.
(*) The best I could find was N0878 from March 1996, which says "A change was recently made to the working paper to add the “Koenig lookup rule”"
First, the example from N0783 for functions:
void f(char);
namespace A {
class B {
friend void f(char); // ::f(char) is a friend
friend void f(int); // A::f(int) is a friend
void bf();
};
void B::bf()
{
f(1); // calls A::f(int);
f('x'); // also calls A::f(int) because ::f is hidden
}
}
The second friend declaration must introduce a new function. N0783 tries to specify in which scope this declaration is introduced. It suggests
All friend declarations for a given name must declare entities in one
particular scope.
as a general rule, to avoid the surprises of situations such as the above.
So the question is, which scope do they declare entities in? There are
two possibilities, either
When looking for a previous declaration of the function, look until the nearest enclosing namespace is reached, or
When looking for a previous declaration, look in all enclosing scopes for the name of the function that was declared. If a previous
use of the name is found, the declaration is injected into that scope.
If no previous use of the name is found the friend is injected into
the nearest enclosing namespace scope.
Rule #2 would mean that the presence of any function called f in an
enclosing scope, whether or not the types match, would be enough to
cause a friend declaration to inject into that scope.
I believe that rule #2 is clearly unacceptable. A friend declaration
in a namespace would be affected by any global declaration of that
name. Consider what this would mean for operator functions! The
presence of any operator+ function in the global scope would force
all friend operator+ operators to appear in the global scope too!
The presence of a template in the global scope would have the same
effect.
For class types:
namespace N {
class A { void f(); };
}
using namespace N;
namespace M {
class B {
friend class A; // Without this rule
// makes N::A a friend
B();
};
class A { void f(); };
}
void N::A::f() { M::B b; } // A friend under current rules
void M::A::f() { M::B b; } // A friend under proposed rules
Both examples are not as interesting under the current rules because names introduced via friend declarations are only found via ADL. It is possible this restriction is a historical artefact. More "research" is required to follow the development of this restriction after the introduction of ADL.

Confusion around function call resolution

This question is inspired by this one. Consider the code:
namespace ns {
template <typename T>
void swap(T& a, T& b) {
using namespace std;
swap(a, b);
}
}
After some test with GCC, I found that swap(a, b); resolves to
1) std::swap if T has overloaded std::swap (e.g., standard container types)
2) ns::swap otherwise, leading to infinite recursion.
So, it seems that the compiler will first try to find a match in the namespace ns. If a match is found, the search ends. But this is not the case when ADL comes in, in which case, std::swap is found anyway. The resolution process seems to be complicated.
I want to know the details of what is going on under the hood in the process of resolving the function call swap(a, b) in the above context. Reference to the standard would be appreciated.
The code in the OP is equivalent to this:
using std::swap; // only for name lookup inside ns::swap
namespace ns {
template <typename T>
void swap(T& a, T& b) {
swap(a, b);
}
}
Why? Because using-directives like using namespace std; have a very peculiar behaviour C++14 [namespace.udir]p2:
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, the names
appear as if they were declared in the nearest enclosing namespace
which contains both the using-directive and the nominated namespace.
The nearest enclosing namespace that contains both namespace std and the block scope of function ns::swap is the global namespace.
Using-declarations such as using std::swap; on the other hand really introduce names into the scope in which they appear, not in some enclosing scope.
The lookup of a function call expression such as swap(a, b) is called unqualified lookup. The identifier swap has not been qualified with any namespace or class name, as opposed to ns::swap, which has been qualified via ns::. Unqualified lookup for potential names of functions consists of two parts: pure unqualified lookup and argument-dependent lookup.
Pure unqualified lookup stops at the nearest enclosing scope that contains the name. In the OP's example, as illustrated by the equivalent transformation shown above, the nearest scope that contains a declaration of the name swap is the namespace ns. The global scope will not be searched, std::swap will not be found via pure unqualified lookup.
Argument-dependent lookup searches all scopes (here: only namespaces and classes) associated with the argument types. For class types, the namespace in which the class has been declared in is an associated scope. Types of the C++ Standard Library such as std::vector<int> are associated with namespace std, hence std::swap can be found via argument-dependent lookup for the expression swap(a, b) if T is a C++ Standard Library type. Similarly, your own class types allow finding a swap function in the namespaces they have been declared in:
namespace N2 {
class MyClass {};
void swap(MyClass&, MyClass&);
}
Therefore, if argument-dependent lookup does not find a better match than pure unqualified lookup, you'll end up calling ns::swap recursively.
The idea behind calling swap unqualified, that is, swap(a, b) instead of std::swap(a, b) is that functions found via argument-dependent lookup are assumed to be more specialized than std::swap. Specializing a function template such as std::swap for your own class template type is impossible (since partial function template specializations are forbidden), and you may not add custom overloads to namespace std. The generic version of std::swap is implemented typically as follows:
template<typename T>
void swap(T& a, T& b)
{
T tmp( move(a) );
a = move(b);
b = move(tmp);
}
This requires a move-construction plus two move-assignments, which might even fall back to copies. Therefore, you can provide a specialized swap function for your own types in the namespaces associated with those types. Your specialized version can make use of certain properties of, or private access to, your own types.
The most important piece of the standard is 7.3.4/2 (quoting C++14 n4140, emphasis mine):
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.
The using-directive is located inside a function in :: ns, and nominates :: std. This means that for the purpose of unqualified name lookup, the effect of this using-directive is that names in ::std behave as if they were declared in ::. Particularly, not as if they were in ::ns.
Because the unqualified name lookup begins inside a function in ::ns, it will search ::ns before looking into ::. And it finds ::ns::swap, so it ends there, without examining ::, where it would find ::std::swap brought in by the using-directive.