void f() {}
namespace A {
void f(int);
using ::f; /// <<<< seems to hide above declaration
}
// The following line generates this message [g++]
// /tmp/asdf.cpp:8: error: 'void A::f(int)' should have been declared
inside 'A'
void A::f(int a) {}
int main() {
A::f(1);
}
In my opinion, it clearly is declared inside 'A', but the "using ::f"
declaration causes g++ to not see it. I reported this as a bug (gcc
bug 38799) but it was closed as "this is how it should behave." When
I reverse the order of those statements (such that the ::using comes
first, then g++ accepts the code without error.
I've not found any conclusive (to me) language in the standard about
this, but do notice that Comeau accepts this code, with and without c+
+0x extensions. I place a great deal of faith in Comeau/EDG, and
usually find that when I think I've found a bug in Comeau, it usually
turns into an opportunity for me to learn something new.
Can someone explain which compiler is correct, and if this error as
reported by g++ really is the intended behavior of the language,
please explain the motivation for it?
Thanks!
Chris
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
> I was surprised to find that g++ (as of 4.3 and 4.4) rejects this
> code:
>
> void f() {}
>
> namespace A {
> void f(int);
> using ::f; /// <<<< seems to hide above declaration
> }
> In my opinion, it clearly is declared inside 'A', but the "using ::f"
> declaration causes g++ to not see it. I reported this as a bug (gcc
> bug 38799) but it was closed as "this is how it should behave." When
> I reverse the order of those statements (such that the ::using comes
> first, then g++ accepts the code without error.
>
> I've not found any conclusive (to me) language in the standard about
> this, but do notice that Comeau accepts this code, with and without c+
> +0x extensions. I place a great deal of faith in Comeau/EDG, and
> usually find that when I think I've found a bug in Comeau, it usually
> turns into an opportunity for me to learn something new.
As I read the standard [7.3.4], Cameau is right.
using declaration most of the time works exactly like a normal declaration,
with the similar effect. The one exception I found is with member functions
where collision is processed as 'hide' instead of 'conflict'. What makes
sense.
Otherwise, function declarations made at the *same* declaration scope never
hide each other -- hiding applies only to declarations of an outer scope.
Your example would translate to
namespace A {
void f(int);
void f(); // mapping to ::f()
// note: if multiple functions are there all are dragged in
}
that is a good overload set. The order of the declarations is not important
for this case.
If you change ::f to be f(int), Cameat flags a conflict, as is should too.
(And the conflict goes away if code turned to member functions).
In summary IMO g++ guys are wrong. Did they say where their idea of hiding
*siblings* comes from?
> "Chris Uzdavinis" <cuz...@gmail.com>
>
>> I was surprised to find that g++ (as of 4.3 and 4.4) rejects this
>> code:
>>
>> void f() {}
>>
>> namespace A {
>> void f(int);
>> using ::f; /// <<<< seems to hide above declaration
>> }
>
>> In my opinion, it clearly is declared inside 'A', but the "using ::f"
>> declaration causes g++ to not see it. I reported this as a bug (gcc
>> bug 38799) but it was closed as "this is how it should behave." When
>> I reverse the order of those statements (such that the ::using comes
>> first, then g++ accepts the code without error.
>>
>> I've not found any conclusive (to me) language in the standard about
>> this, but do notice that Comeau accepts this code, with and without c+
>> +0x extensions. I place a great deal of faith in Comeau/EDG, and
>> usually find that when I think I've found a bug in Comeau, it usually
>> turns into an opportunity for me to learn something new.
>
> Your example would translate to
>
> namespace A {
> void f(int);
> void f(); // mapping to ::f()
> // note: if multiple functions are there all are dragged in
> }
> that is a good overload set. The order of the declarations is not
> important for this case.
>
> If you change ::f to be f(int), Cameat flags a conflict, as is should
> too. (And the conflict goes away if code turned to member functions).
>
> In summary IMO g++ guys are wrong. Did they say where their idea of hiding
> *siblings* comes from?
>
>
Maybe they are reading 8.3/1 as saying that the qualified-id in that
declaration outside the namespace may not refer to an overload set
containing a using declaration? 8.3/1 says:
"... the declaration shall refer to a previously declared member of the
class or namespace to which the qualifier refers, and the member shall not
have been introduced by a using-declaration in the scope of the class or
namespace nominated by the nested-name-specifier of the declarator-id."
The declaration arguably does only refer to one function, but its qualified-
id when looked-up before considering context refers to both functions in
"A". Maybe GCC is making the test before or during declaration matching, and
not afterwards? I think they seem to do it *during* matching using a simple
loop: If the using declaration is found first, they error out. But if the
matching non-using declaration is found first, they stop that loop.
That makes sense, but does not apply in the case.
void f() {}
namespace A {
void f(int);
using ::f; /// <<<< seems to hide above declaration
}
void A::f(int a) {}
here f is a member of A and f(int) is a genuine thing. This would make
things
void A::f() {} // f is member but introduced with using
void A::g() {} // not member
Btw any argument about 'hiding' gets fishy with a qualified-id. hiding is a
feature applied to unqualified lookup.
> The declaration arguably does only refer to one function, but its
> qualified-
> id when looked-up before considering context refers to both functions in
> "A".
Sure. That doesn't make them not-declared. ;)
> Maybe GCC is making the test before or during declaration matching, and
> not afterwards? I think they seem to do it *during* matching using a
> simple
> loop: If the using declaration is found first, they error out.
Aha, that is technically possible -- when they process using, mark
everything. Or do some other kind of mis-booking, on f(int).
> But if the
> matching non-using declaration is found first, they stop that loop.
I'm sure the compiler doesn't work like that -- it is not looking source
text any longer, but has a symbol table built. When true-member f comes
last, it is put correctly in the table. With the other sequence some info
is corrupted, manifesting in the bug.