Может ли выражение throw или delete когда-либо зависеть?

Для gcc 5.0 и clang 3.6 требуется typename Ключевое слово в следующем примере:

template<typename T>
struct B
{
typedef int Type;
};

template<int n>
struct A
{
typedef typename B<decltype(throw (int*)n)>::Type Throw;
typedef typename B<decltype(delete (int*)n)>::Type Delete;
};

На это распространяется следующая формулировка в стандарте C ++ 11:

[За исключением] / 2

Выражение броска имеет тип void.

[Expr.delete] / 1

Операнд должен иметь указатель на тип объекта или тип класса, имеющий одно неявное преобразование
функция указателя на тип объекта. Результат имеет тип void.

Итак, я предполагаю decltype производит void в обоих случаях.

[Expr.const] / 2

Условное выражение является основным константным выражением, если оно не включает одно из следующих
оцениваемое подвыражение

  • новое выражение

  • выражение броска

Это говорит о том, что выражение, включающее либо throw или же delete не может быть постоянным выражением.

[Temp.dep.type] / 8

Тип зависит, если он

  • простой-шаблон-идентификатор, в котором либо имя шаблона является параметром шаблона, либо любым из шаблона
    Аргументы являются зависимым типом или выражением, которое зависит от типа или значения

  • обозначается decltype(expression)где выражение зависит от типа

Так B<decltype(..)> зависит, только если выражение зависит от типа.

[Temp.dep.expr] / 4

Выражения следующих форм никогда не зависят от типа (потому что тип выражения не может быть
зависимая):

delete cast-expression
throw assignment-expression

Это говорит о том, что ни одно выражение не может зависеть от типа.

Gcc и clang не правы?

7

Решение

Давайте вернемся к тому, когда typename необходимо. §14.6 [temp.res] / p3, все цитаты взяты из N4140:

Когда Квалифицированный-идентификатор предназначен для ссылки на тип, который не является
член текущего экземпляра (14.6.2.1) и его
вложенное имя спецификатор относится к зависимому типу, он должен начинаться с ключевого слова typename, образуя имяТипа спецификатор.

Квалифицированный-идентификатор в этом случае B<decltype(throw (int*)n)>::Typedelete версия, для которой анализ точно такой же). Так typename требуется, если вложенное имя спецификатор, или же B<decltype(throw (int*)n)>::относится к зависимому типу.

В §14.6.2.1 [temp.dep.type] / p8 сказано, что шесть не связанных между собой пуль не указано, что

Тип зависит, если он

[…]

(8.7) простой шаблон-идентификатор в котором либо имя шаблона является
Параметр шаблона или любой из аргументов шаблона является зависимым
тип или выражение, которое зависит от типа или значения, или

(8.8) — обозначается decltype(выражение), где выражение зависит от типа (14.6.2.2).

B<decltype(throw (int*)n)> это простой шаблон-идентификатор. Название шаблона, B, не является параметром шаблона. Единственный аргумент шаблона, decltype(throw (int*)n), это не выражение, так B<decltype(throw (int*)n)> зависит только если decltype(throw (int*)n) это зависимый тип. decltype(throw (int*)n)в свою очередь, в соответствии с пулей 8.8, зависит только, если throw (int*)n зависит от типа. Но мы знаем, что согласно §14.6.2.2 [temp.dep.expr] / p4:

Выражения следующих форм никогда не зависят от типа (потому что
тип выражения не может быть зависимым):

[…]

::выбирать delete монолитно-выражение

[…]

throw Назначение выражениевыбирать

[…]

Следовательно, throw (int*)n не зависит от типа, и так decltype(throw (int*)n) это не зависимый тип, и так B<decltype(throw (int*)n)> это не зависимый тип, и так typename не требуется для B<decltype(throw (int*)n)>::Typeи так да, это ошибка компилятора.

7

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


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