Указывает ли `decltype` мне статический тип объекта или его тип времени выполнения? - программирование
Подтвердить что ты не робот

Указывает ли `decltype` мне статический тип объекта или его тип времени выполнения?

[C++11: 7.1.6.2/4]: Тип, обозначенный символом decltype(e), определяется следующим образом:

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

Операндом спецификатора decltype является неоцениваемый операнд (пункт 5).

Второй, третий и четвертый случаи явно относятся к типу выражения, которое не включало бы никаких соображений полиморфизма.

Однако, и я не совсем уверен, что здесь означает "сущность", первый случай, как представляется, обозначает объект, на который ссылается выражение e. Для меня двусмысленно говорить о том, означает ли "тип объекта" его тип времени выполнения или его статический тип.

4b9b3361

Ответ 1

На самом деле невозможно справиться с этой проблемой из-за ограничений этого первого случая.

Рассмотрим:

struct A     {};
struct B : A {};

int main()
{
   A* x = new B();
   // What is `decltype(*x)`?
}

Использование * заставляет нас провалиться в третий случай.

А для ссылок?

struct A     {};
struct B : A {};

int main()
{
   A& x = *(new B());
   // What is `decltype(x)`?
}

x является ссылкой с типом A&, и именно эта "сущность" имеет тип результата.

Единственный способ использовать первый случай - прямое имя объекта, и мы не можем сделать это так, чтобы скрывать тип среды выполнения:

struct A     {};
struct B : A { void foo() {} };

int main()
{
   A x = B();     // well, you've sliced it now, innit?

   decltype(x) y;
   y.foo();       // error: ‘struct A’ has no member named ‘foo’
}

Вот почему, согласно этим ответам, это всегда статический тип используемого объекта.

Ответ 2

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

Ответ 3

В основном вопрос о том, что здесь означает "сущность" (возможные значения определены в разделе 3). Рассмотрим

struct A {
  int a;
};

int main() {
  A a = {};
  const A b = {};

  const A *aptr = (rand() % 42) ? &a : &b;
  decltype(aptr->a) x = 0;
  decltype((aptr->a)) y = 0;
}

Является ли x типом const int или int? Если вы принимаете сущность для обозначения "член", она int, потому что член A::a имеет тип int. Если вы возьмете объект "объект" объекта, то тип будет либо const int, либо int, в зависимости от результата rand(). Объекты, их существование и свойства (включая их тип в целом) - это проблема времени выполнения.

Я говорю, что это не настоящая двусмысленность. Потому что все знают, что имеется в виду, и потому, что Стандарт использует фразу "named by e", а не "обозначается буквой e" или "обозначается буквой e", указывая на то, что с ней обращаются только результаты поиска по имени.

Обратите внимание, что тип y всегда const int&, потому что тип выражения aptr->a равен const int и это значение l.