How do the keywords typename/template interact with using-declarations?
9.9 [namespace.udecl]
Bill Gibbons

Created on 1998-10-24.00:00:00 last changed 168 months ago


Date: 2004-03-15.00:00:00

[Voted into WP at March 2004 meeting.]

Date: 2004-03-15.00:00:00

[Voted into WP at March 2004 meeting.]

Date: 2003-04-15.00:00:00

Proposed resolution (April 2003, revised October 2003):

Add a new paragraph to the bottom of 9.9 [namespace.udecl]:

If a using-declaration uses the keyword typename and specifies a dependent name (13.8.3 [temp.dep]), the name introduced by the using-declaration is treated as a typedef-name (9.2.4 [dcl.typedef]).
Date: 2003-04-15.00:00:00

Notes from the April 2003 meeting:

This was reopened because we are now considering extensions again. We agreed that it is desirable for the typename to be "sticky" on a using-declaration, i.e., references to the name introduced by the using-declaration are known to be type names without the use of the typename keyword (which can't be specified on an unqualified name anyway, as of now). The related issue with the template keyword already has a separate issue 109.

Issue 2 deals with the "struct hack." There is an example in 9.9 [namespace.udecl] paragraph 10 that shows a use of using-declarations to import two names that coexist because of the "struct hack." After some deliberation, we decided that the template-dependent using-declaration case is different enough that we did not have to support the "struct hack" in that case. A name introduced in such a case is like a typedef, and no other hidden type can be accessed through an elaborated type specifier.

Date: 2022-02-18.07:47:23

Issue 1:

The working paper is not clear about how the typename/template keywords interact with using-declarations:

     template<class T> struct A {
         typedef int X;

     template<class T> void f() {
         typename A<T>::X a;      // OK
         using typename A<T>::X;  // OK
         typename X b;  // ill-formed; X must be qualified
         X c;  // is this OK?
When the rules for typename and the similar use of template were decided, we chose to require that they be used at every reference. The way to avoid typename at every use is to declare a typedef; then the typedef name itself is known to be a type. For using-declarations, we decided that they do not introduce new declarations but rather are aliases for existing declarations, like symbolic links. This makes it unclear whether the declaration "X c;" above should be well-formed, because there is no new name declared so there is no declaration with a "this is a type" attribute. (The same problem would occur with the template keyword when a member template of a dependent class is used). I think these are the main options:
  1. Continue to allow typename in using-declarations, and template (for member templates) too. Attach the "is a type" or "is a template" attribute to the placeholder name which the using-declaration "declares"
  2. Disallow typename and template in using-declarations (just as class-keys are disallowed now). Allow typename and template before unqualified names which refer to dependent qualified names through using-declarations.
  3. Document that this is broken.
Suggested Resolution:

The core WG already resolved this issue according to (1), but the wording does not seem to have been added to the standard. New wording needs to be drafted.

Issue 2:

Either way, one more point needs clarification. If the first option is adopted:

     template<class T> struct A {
         struct X { };

     template<class T> void g() {
         using typename A<T>::X;
         X c;    // if this is OK, then X by itself is a  type
         int X;  // is this OK?
When "g" is instantiated, the two declarations of X are compatible (9.9 [namespace.udecl] paragraph 10) . But there is no way to know this when the definition of "g" is compiled. I think this case should be ill-formed under the first option. (It cannot happen under the second option.) If the second option is adopted:
     template<class T> struct A {
         struct X { };

     template<class T> void g() {
         using A<T>::X;
         int X;  // is this OK?
Again, the instantiation would work but there is no way to know that in the template definition. I think this case should be ill-formed under the second option. (It would already be ill-formed under the first option.)

From John Spicer:

The "not a new declaration" decision is more of a guiding principle than a hard and fast rule. For example, a name introduced in a using-declaration can have different access than the original declaration.

Like symbolic links, a using-declaration can be viewed as a declaration that declares an alias to another name, much like a typedef.

In my opinion, "X c;" is already well-formed. Why would we permit typename to be used in a using-declaration if not to permit this precise usage?

In my opinion, all that needs to be done is to clarify that the "typeness" or "templateness" attribute of the name referenced in the using-declaration is attached to the alias created by the using-declaration. This is solution #1.

Tentative Resolution:

The rules for multiple declarations with the same name in the same scope should treat a using-declaration which names a type as a typedef, just as a typedef of a class name is treated as a class declaration. This needs drafting work. Also see Core issue 36.

Rationale (04/99): Any semantics associated with the typename keyword in using-declarations should be considered an extension.

Date User Action Args
2008-10-05 00:00:00adminsetstatus: wp -> cd1
2004-04-09 00:00:00adminsetmessages: + msg1011
2004-04-09 00:00:00adminsetstatus: ready -> wp
2003-11-15 00:00:00adminsetstatus: review -> ready
2003-04-25 00:00:00adminsetmessages: + msg824
2003-04-25 00:00:00adminsetmessages: + msg823
2003-04-25 00:00:00adminsetstatus: open -> review
2002-11-08 00:00:00adminsetstatus: extension -> open
1999-09-14 00:00:00adminsetmessages: + msg199
1999-09-14 00:00:00adminsetstatus: drafting -> extension
1998-10-24 00:00:00admincreate