Подтвердить что ты не робот

Тип (x) в С++

Дано:

decltype(auto) f1()
{
    int x = 0;
    return x;  // decltype(x) is int, so f1 returns int
}
decltype(auto) f2()
{
    int x = 0;
    return (x);  // decltype((x)) is int&, so f2 returns int&
}

(Взято из Скотта Майера "Эффективный современный С++" ).

Теперь, если я нашел правильный параграф, Раздел 7.1.5.2 Спецификаторы простого типа [dcl.type.simple] стандарта С++ говорят:

Если e является id-выражением или доступом к члену класса (5.2.5 [expr.ref]), decltype (e) определяется как тип объекта, названного e

и пример из этого раздела:

struct A { double x; }

const A* a = new A();

decltype((a->x)); // type is const double&

Теперь, интересно, почему в decltype((x)) выводится int& в книге.

4b9b3361

Ответ 1

Соответствующая стандартная цитата:

N4140 [dcl.type.simple]/4: Для выражения e тип, обозначенный символом decltype(e), определяется следующим образом:

  • если e - это несферированное id-выражение или unparenthesized доступ к члену класса (5.2.5), decltype(e)это тип объекта с именем e. Если такой объект отсутствует или если e называет набор перегруженных функций, программа плохо сформирована;
  • в противном случае, если e - значение x, decltype(e) - T&&, где T - тип e;
  • в противном случае, если e является lvalue, decltype(e) является T&, где T - тип e;
  • в противном случае decltype(e) является типом e.

Так как x является lvalue, а выражение заключено в скобки, используется третье правило, поэтому decltype((x)) является int&.

Ответ 2

decltype возвращает объявленный тип переменной или "тип" выражения (с некоторой ссылкой, добавленной для указания ценности l/r).

Это позволяет использовать его в двух разных целях. Иногда это вызывает путаницу, но это то, что есть.

Токен x является переменной. Тип переменной int.

Токены (x) не являются переменной, а скорее (действительно тривиальным) выражением, содержащим только одну переменную. Таким образом, тип выражения (как определено методом decltype) (x) равен int&.

Тип выражения x (если вы могли бы убедить decltype дать его вам, вы не можете) также int&, но правило, которое decltype(ACTUAL_VAR_NAME) оценивает по типу переменной "выигрывает",.

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

Ответ 3

§ 7.1.6.4 [dcl.spec.auto] (проект n3797)

  1. ... Если заполнитель является decltype (авто) Тип Спецификатор, объявленный тип переменной или тип возврата функции должна быть только заполнителем. Определяется тип, выводимый для переменной или типа возврата. как описано в 7.1.6.2, как будто инициализатор был операндом decltype.

§ 7.1.6.2 [dcl.type.simple]

  1. Для выражения е, тип, обозначаемый decltype (е) определяется следующим образом:

-  если е является несферонизированным ID-выражение или несанкционированный доступ к члену класса ( 5.2.5), decltype (е) является типом объекта, названного е, Если такого лица нет или если е называет набор перегруженных func- программа плохо организована,

-  в противном случае, если е является значением x, decltype (е) является Т & &, где T является типом е;

-  в противном случае, если е является lvalue, decltype (е) является Т &, где T является типом е;

-  в противном случае, decltype (е) является типом е

x is is unparenthesized id-expression, поэтому возвращаемый тип выводится как тип x: int

(x) не является выражением id un в скобках, поэтому это правило не применяется. Тем не менее, это выражение (значение в скобках) lvalue. Поэтому выведенный тип T&, где T - тип x: int&

Ответ 4

[dcl.spec.auto]/7 указывает, что, грубо говоря, возвращаемый тип получается, применяя decltype к выражению в выражении return. Таким образом, как следует из комментария, мы ищем decltype((x)). Чрезвычайно правильное правило:

введите описание изображения здесь

Обратите внимание, что первая точка маркера не применяется, поскольку выражение заключено в скобки. Отсюда получаем int&.


Это различие между приложениями decltype на простых идентификаторах и в скобках было введено с ревизией 6 соответствующей статьи. См. В версия 5, §2.3:

Тип, обозначенный decltype(e), определяется следующим образом:

  • Если e имеет вид (e1), decltype(e) определяется как decltype(e1).

Обоснованием этого является, по-видимому, следующее: Написание (x) программист намеревается decltype не обрабатывать операнд как имя, а скорее выражение - учитывая его категорию значений.

Ответ 5

Как уже указывал @Columbo, (a- > x) следует принимать как выражение, а выражение const квалифицировано, потому что * a is const.

Рассмотрим это

decltype((a->x)); 

не был const квалифицированным.

Затем, например, это

decltype((a->x)) ref = (a->x); 

будет неявно сортировать - снять квалификатор * const, потому что * x x станет изменяемым через ref.