Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Name lookup in using-declaration via using-directive

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:

  • Clang (http://melpon.org/wandbox/permlink/c8vl7XbumyyS6vsw): No errors.
  • GCC (http://melpon.org/wandbox/permlink/immhNeWFCMcCA800): Error: 'i' not declared.

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.

like image 321
Supremum Avatar asked Jul 25 '15 16:07

Supremum


People also ask

What is difference between using declaration and using directive?

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 .

What is the use of using declaration in C++?

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 .

What are the difference between using namespace directive and using declaration for accessing namespace member?

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.

What is the use of using declaration?

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.


1 Answers

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 name m, the namespace-qualified lookup set S(X,m) is defined as follows: Let S'(X,m) be the set of all declarations of m in X and the inline namespace set of X (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 in X 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.

like image 103
bogdan Avatar answered Sep 19 '22 02:09

bogdan