Re: name lookup and unnamed namespaces
Daniel Kr?gler wrote:
James Kanze schrieb:
[...]
The fact that in this second example, the function call is not
in a template. There is only one context for lookup, which is
where the function call is written. (Think of it for a minute.
The function call in ostream_iterator is in <iterator>. Your
operator hasn't been declared at all yet.) In this context,
names found by both normal lookup and ADL are considered; normal
lookup at the point of the call finds your function, and so it
works.
Hmmh, forgive me, but I don't understand your reasoning:
What do you mean with "the function call is not in a template"?
Just that I didn't look far enough into the actual code:-). I
was only looking at the call to K<>::f.
Let me replicate the calling point of the 2nd OP example here:
namespace N{
template <class T> struct K
{
void f(const T& t) { g(t); }
};
}
As I see it, g is called inside a member function of the
class template ::N::K. The call is under dependent lookup
conditions, because g is called unqualified with an argument
t which has type T, which is the template parameter. As far
as I see, this call fulfills all conditions of ADL.
Yes. The call to g() is a dependant lookup. At first glance,
the main (only?) difference I see is that there isn't a g() in
namespace N to find (and ADL wouldn't look in N anyway, I
think---but I'll be quite frank and say that I have a great deal
of trouble understanding all this, and figuring out what really
should happen).
Since I like to learn, I would like to present what I think
happens (or should happen), so please point out, what
is wrong in my argumentation. For easier analysis I
repeat the complete code added with some annotations:
namespace N {
template <class T> struct K {
void f(const T& t) { g(t); } // (a)
};
}
using namespace N;
class C {};
namespace {
void g(const C&) {}
}
// (b)
int main() {
K<C> k;
k.f(C());
}
The call of g at point (a) should be a dependent one,
because its argument t is of dependent on T, such we
should have all conditions for dependent lookup. Under
these conditions we should have 2 phase lookup. The
first phase uses ordinary lookup and does not find
any match here, because ordinary lookup takes everything
into account, that occurs lexically before (a). There
is nothing to find here (Note: In the case of the first
example the compiler could possibly find other overloads
of operator<< from namespace std at this stage, if these
were #included before the definition of
::std::ostream_iterator<T, ..>::operator=(const T&); But
this is an implementation-depended issue).
That's an interesting point you make. The results in such cases
depend on the order of user includes and whether specific system
headers include other headers or not. The user's original code
included <ostream> before including <iterator>---if we suppose
that <ostream> does not include <iterator> (although it might, I
suspect that it usually doesn't), then he is guaranteed that the
other << operators are visible when ostream_iterator is defined.
If he inverted the order of the includes, it would depend on
whether <iterator> included <ostream>; I suspect that many do
(since it is useful when defining ostream_iterator), but it
certainly isn't guaranteed.
Since K has no member g, it is also not found as immediate
member of K.
In the second phase we have to consider the instantiation point.
According to instantiation rules, the POI of K<C> should occur
at the point (b). In this phase *only* ADL is taken into account,
I think that's misleading. Because the name is dependant,
lookup occurs in phase 2, and phase 2 in fact uses two separate
lookups: one at the point of definition (in the header file),
and the second at the point of instantiation. It is only in the
second that only ADL is taken into account.
that means, because C is of class type, that according to
3.4.2 p. 2:
- "its associated classes are: the class itself; the class of
which it is a member, if any; and its direct and indirect base
classes. Its associated namespaces are the namespaces
in which its associated classes are defined."
According to the following para 2a:
"If the ordinary unqualified lookup of the name finds the declaration
of a class member function, the associated namespaces and
classes are not considered."
I'm not sure how this applies here. If I define a class and its
operator<< in a namespace, e.g.:
namespace N {
class C {} ;
std::ostream& operator<<( std::ostream&, C const& ) ;
}
it will be found in std::ostream_iterator. (At least, I
certainly hope so.) Even though ordinary unqualified lookup at
the point of definition finds a number operator<< (remember, the
definition is in namespace std::, so ordinary lookup looks
there), and this operator can only be found by ADL in the lookup
at the point of instantiation.
we have to proceed with the seach, because there is no
function member ::N::K<..>::g found. These rules are explained as
"Otherwise the set of declarations found by the lookup of the
function name is the union of the set of declarations found using
ordinary unqualified lookup and the set of declarations found
in the namespaces and classes associated with the argument types."
The set of declarations found via ordinary lookup was empty.
C is defined in the global namespace, where we do not have
any ::g().
There indeed exists a function g() inside an unnamed
namespace, which should behave according to 7.3.1.1 p. 1
as-if a using directive would exist:
namespace "some_unique_identifier" {}
using namespace "some_unique_identifier";
namespace "some_unique_identifier" {
void g(const C&){}
}
Although at point (b) the function "some_unique_identifier"::g
*could* be seen (e.g. under the rules of ordinary lookup), this
case is explicitly exluded from ADL via 3.4.2 p 3:
"Any using-directives in the associated namespace are ignored."
At this point I don't see, how g could be found in this example.
I don't either:-). But I don't claim to understand this very
well. The difference is obviously (?) due to the fact that the
unqualified lookup at the point of definition finds function
definitions in one case, and that it doesn't in the other.
Quite frankly, I'm completely lost.
--
James Kanze (Gabi Software) email: james.kanze@gmail.com
Conseils en informatique orient?e objet/
Beratung in objektorientierter Datenverarbeitung
9 place S?mard, 78210 St.-Cyr-l'?cole, France, +33 (0)1 30 23 00 34
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]