C ++ decltype и круглые скобки - почему? - PullRequest
32 голосов
/ 24 февраля 2020

Тема была обсуждена до , но это не дубликат.

Когда кто-то спрашивает о разнице между decltype(a) и decltype((a)), обычный ответ - a - переменная, (a) - выражение. Я нахожу этот ответ неудовлетворительным.

Во-первых, a также является выражением. Опции для основного выражения включают, среди прочего -

  • (выражение)
  • id-выражение

Что еще более важно, формулировка для decltype рассматривает скобки очень и очень явно :

For an expression e, the type denoted by decltype(e) is defined as follows:
(1.1)  if e is an unparenthesized id-expression naming a structured binding, ...
(1.2)  otherwise, if e is an unparenthesized id-expression naming a non-type template-parameter, ...
(1.3)  otherwise, if e is an unparenthesized id-expression or an unparenthesized class member access, ...
(1.4)  otherwise, ...

Таким образом, вопрос остается. Почему обрабатываются в скобках по-разному? Кто-нибудь знаком с техническими документами или обсуждениями в комитете? Явное рассмотрение скобок заставляет думать, что это не упущение, поэтому должна быть техническая причина, по которой я скучаю.

Ответы [ 3 ]

18 голосов
/ 24 февраля 2020

Это не недосмотр. Интересно, что в Decltype и auto (редакция 4) (N1705 = 04-0145) есть утверждение:

В правилах decltype теперь явно указывается, что decltype((e)) == decltype(e) ( как предложено EWG).

Но в Decltype (редакция 6): предлагаемая формулировка (N2115 = 06-018) одно из изменений

Заключенное в скобки выражение внутри decltype не считается id-expression.

В формулировке нет никакого смысла, но я предполагаю, что это своего рода расширение decltype с использованием немного другого синтаксиса, другими словами, это было предназначено для дифференциации этих случаев.

Использование этого показано в C ++ draft9.2.8.4:

const int&& foo();
int i;
struct A { double x; };
const A* a = new A();
decltype(foo()) x1 = 17;        // type is const int&&
decltype(i) x2;                 // type is int
decltype(a->x) x3;              // type is double
decltype((a->x)) x4 = x3;       // type is const double&

Что действительно интересно, так это то, как он работает с оператором return:

decltype(auto) f()
{
    int i{ 0 };
    return (i);
}

Моя Visual Studio 2019 предлагает мне удалить лишние скобки, но на самом деле они превращаются в decltype((i)), который меняет возвращаемое значение на int&, что делает его UB, так как возвращение ссылки на локальную переменную.

13 голосов
/ 24 февраля 2020

Почему скобки обрабатываются по-разному?

Круглые скобки не обрабатываются по-разному. Это не заключенное в скобки id-выражение, которое обрабатывается по-разному.

Когда присутствуют скобки, применяются обычные правила для всех выражений. Тип и категория значения извлекаются и кодируются в виде decltype.

. Существует специальное положение, чтобы мы могли легче писать полезный код. Применяя decltype к имени переменной (member), мы обычно не хотим, чтобы какой-либо тип представлял свойства переменной, когда она рассматривается как выражение. Вместо этого нам нужен только тип, с которым объявлена ​​переменная, без необходимости применять тонну свойств типа, чтобы получить ее. И это именно то, что указано для decltype.

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

1 голос
/ 01 марта 2020

Pre C ++ 11 языку нужны инструмент (ы) для получения двух разных видов информации :

  • тип выражения
  • the тип переменной в том виде, в котором он был объявлен

Из-за характера этой информации функции должны были быть добавлены на языке (это нельзя сделать в библиотеке). Это означает, что новое ключевое слово (ы). Стандарт мог бы ввести два новых ключевых слова для этого. Например, exprtype для получения типа выражения и decltype для получения типа объявления переменной. Это был бы ясный, счастливый вариант.

Однако комитет по стандартизации всегда изо всех сил старался избегать введения новых ключевых слов в язык, чтобы свести к минимуму поломку старого кода. Обратная совместимость является основной философией языка.

Итак, с C ++ 11 мы получили только одно ключевое слово, используемое для двух разных вещей: decltype. Различие между этими двумя видами использования заключается в различном подходе к decltype(id-expression). Это было сознательное решение комитета, (небольшой) компромисс.

...