7

Draft N3337 of the C++11 standard states in [namespace.udecl]

A using-declaration introduces a name into the declarative region in which the using-declaration appears.

Every using-declaration is a declaration and a member-declaration and so can be used in a class definition.

In a using-declaration used as a member-declaration, the nested-name-specifier shall name a base class of the class being defined.

This is generally used to make a protected typedef within a base-class public in the derived class, as in the following example, which compiles successfully in the latest version of Clang:

struct A
{
protected:
    typedef int Type;
};

struct B : A
{
    using A::Type;
};

B::Type x;

The using-declaration can refer to a template class. This compiles:

struct A
{
protected:
    template<typename T>
    struct Type
    {
    };
};

struct B : A
{
    using A::Type;
};

B::Type<int> x;

It's also possible to refer to a template in a dependent base-class. The following compiles successfully (with the typedef commented.)

template<typename T>
struct A
{
protected:
    template<typename U>
    struct Type
    {
    };
};


template<typename T>
struct B : A<T>
{
    using /* typename */ A<T>::Type; // A<T> is dependent, typename required?
    // typedef Type<int> IntType; // error: unknown type name 'Type'
};

B<int>::Type<int> x;

Uncommenting the typename causes an error when instantiating B<int>: "error: 'typename' keyword used on a non-type".

Uncommenting the typedef causes an error when parsing B before its first instantiation. I'm guessing this is because the compiler does not treat Type as a dependent type-name.

The last paragraph of [namespace.udecl] suggests that using-declarations may specify dependent names, and that the typename keyword must be used in order to disambiguate further usage of the name introduced:

If a using-declaration uses the keyword typename and specifies a dependent name (14.6.2), the name introduced by the using-declaration is treated as a typedef-name

My reading of [temp.dep] suggests that A<T>::Type is a dependent name. It follows logically that the name introduced by the using-declaration should also be dependent, but [temp.dep] does not explicitly mention the case of a dependent using-declaration. Am I missing something?

willj
  • 2,991
  • 12
  • 24

2 Answers2

2

The problem is that Type is not a class, but a class template. You can do the following (this way you tell the compiler that Type is a class template in scope of B):

template<typename T>
struct B : A<T>
{
    using A<T>::Type;
    typedef typename B::template Type<int> IntType;
};

Actually, in your second example in order to write typedef for IntType you'd have to do the same.

Anton Savin
  • 40,838
  • 8
  • 54
  • 90
  • As Anton pointed out (before editing the answer) the complication is that the using-declaration syntax does not provide a way to specify that a dependent name is a template. Subsequent use of the dependent name `Type` within `B` cannot know that it is a template, so `Type` cannot be parsed. – willj Nov 26 '14 at 21:20
  • That's a good example of a seemingly valid usage of a dependent using-declaration. It seems safe to assume that dependent using-declarations introduce dependent names. – willj Nov 27 '14 at 12:22
  • According to [temp.dep.type], The additional qualifying `B::` makes `Type` into a "member of an unknown specialization": `B::Type` names a dependent type. – willj Nov 27 '14 at 18:48
0

Yes, a class-member using-declaration with a dependent qualified-id introduces a dependent name.

[namespace.udecl]

A using-declaration introduces a name into the declarative region in which the using-declaration appears.

If the name introduced is dependent, it stays dependent - I can find nothing to suggest otherwise.

However, the using-declaration syntax does not provide a way to specify that a dependent name is a template. Subsequent references to the dependent name Type within B may or may not refer to a template, so Type<int> cannot be parsed.

The following example demonstrates valid usage of a dependent using-declaration.

template<typename T>
struct A
{
protected:
    struct Type
    {
        typedef int M;
    };
};


template<typename T>
struct B : A<T>
{
    using typename A<T>::Type;
    typedef typename Type::M Type2;
};

B<int>::Type2 x;
Community
  • 1
  • 1
willj
  • 2,991
  • 12
  • 24