Is the following program well-formed or ill-formed according to the c++ standard?
namespace N { int i; }
using namespace N;
using ::i;
int main() {}
I get different results with different compilers:
Is this program well-formed or ill-formed according to the c++ standard? References to the c++ standard needed.
I'm trying to figure out for which compiler I should file a bug.
The obvious reason is that a using declaration and a using directive have different effects. A using declaration introduces the name immediately into the current scope, so using std::swap introduces the name into the local scope; lookup stops here, and the only symbol you find is std::swap .
A using declaration in a definition of a class A allows you to introduce a name of a data member or member function from a base class of A into the scope of A .
using directives Use a using directive in an implementation file (i.e. *. cpp) if you are using several different identifiers in a namespace; if you are just using one or two identifiers, then consider a using declaration to only bring those identifiers into scope and not all the identifiers in the namespace.
A using declaration introduces an unqualified name as a synonym for an entity declared elsewhere. It allows a single name from a specific namespace to be used without explicit qualification in the declaration region in which it appears.
Well-formed.
The using-directive doesn't introduce the name i
in the global namespace, but it is used during lookup. The using-declaration uses qualified lookup to find i
; qualified lookup in the presence of using-directives is specified in [3.4.3.2 p1, p2] (quotes from N4527, the current working draft):
If the nested-name-specifier of a qualified-id nominates a namespace (including the case where the nested-name-specifier is
::
, i.e., nominating the global namespace), the name specified after the nested-name-specifier is looked up in the scope of the namespace. [...]For a namespace
X
and namem
, the namespace-qualified lookup set S(X,m) is defined as follows: Let S'(X,m) be the set of all declarations ofm
inX
and the inline namespace set ofX
(7.3.1). If S'(X,m) is not empty, S(X,m) is S'(X,m); otherwise, S(X,m) is the union of S(Ni,m) for all namespaces Ni nominated by using-directives inX
and its inline namespace set.
So, for qualified lookup, the first step is to look for declarations of i
made directly in the namespace indicated by the nested-name-specifier (::
in this case). There are no such declarations, so lookup then proceeds to the second step, which is to form the set of all declarations of i
found by qualified lookup in all namespaces nominated by using-directives in the global namespace. That set is comprised of N::i
, which is the result of name lookup, and is introduced as a name in global namespace by the using declaration.
I find it worth noting (although pretty obvious) that this definition of qualified lookup is recursive: using the notation in the quote, qualified lookup in each namespace Ni will first look for declarations made directly in Ni, then, if none is found, will in turn proceed to look in the namespaces nominated by using-directives in Ni, and so on.
For what it's worth, MSVC accepts the code as well.
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