Должно ли объявление использования члена класса с зависимым квалифицированным идентификатором быть зависимым именем?

Проект N3337 стандарта C ++ 11 гласит [namespace.udecl]

Объявление-использование вводит имя в декларативную область, в которой появляется объявление-использование.

Каждое объявление об использовании является объявлением и объявлением члена и поэтому может использоваться в определении класса.

В объявлении использования, используемом в качестве объявления члена, спецификатор nested-name должен называть базовый класс
класс определяется.

Это обычно используется для того, чтобы сделать защищенную typedef внутри общедоступного базового класса в производном классе, как в следующем примере, который успешно компилируется в последней версии Clang:

struct A
{
protected:
typedef int Type;
};

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

B::Type x;

Объявление-использование может ссылаться на класс шаблона. Это компилирует:

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

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

B::Type<int> x;

Также возможно ссылаться на шаблон в зависимом базовом классе. Следующие компиляции успешно (с комментарием typedef.)

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;

Раскомментировать typename вызывает ошибку при создании экземпляра B<int>: «ошибка: ключевое слово ‘typename’, используемое не для типа».

Раскомментирование typedef вызывает ошибку при разборе B до его первого экземпляра. Я предполагаю, что это потому, что компилятор не лечит Type в качестве зависимого имени типа.

Последний абзац [namespace.udecl] предполагает, что использование-объявления могут указывать зависимые имена, и что typename ключевое слово должно использоваться для устранения неоднозначности дальнейшего использования введенного имени:

Если объявление использования использует ключевое слово typename и указывает зависимое имя (14.6.2), вводится имя
с помощью объявления-использования обрабатывается как typedef-имя

Мое чтение [temp.dep] предполагает, что A<T>::Type это зависимое имя. Логично следует, что имя, введенное объявлением использования, также должно быть зависимым, но [temp.dep] явно не упоминается случай зависимого объявления об использовании. Я что-то пропустил?

7

Решение

Проблема в том, что Type это не класс, а шаблон класса. Вы можете сделать следующее (таким образом вы сообщаете компилятору, что Type шаблон класса в области видимости B):

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

На самом деле, во втором примере, чтобы написать typedef за IntType Вы должны сделать то же самое.

2

Другие решения

Да, объявление использования члена класса с зависимым квалифицированным идентификатором вводит зависимое имя.

[Namespace.udecl]

Объявление-использование вводит имя в декларативную область, в которой появляется объявление-использование.

Если введенное имя является зависимым, оно остается зависимым — я не могу найти ничего, что могло бы предложить иначе.

Однако синтаксис объявления использования не позволяет указать, что зависимое имя является шаблоном. Последующие ссылки на зависимое имя Type в B может или не может ссылаться на шаблон, поэтому Type<int> не может быть проанализирован

В следующем примере демонстрируется правильное использование зависимого объявления использования.

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;
0

По вопросам рекламы [email protected]