Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Should a class-member using-declaration with a dependent qualified-id be a dependent name?

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?

like image 762
willj Avatar asked Nov 26 '14 20:11

willj


1 Answers

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.

like image 73
Anton Savin Avatar answered Sep 20 '22 12:09

Anton Savin