Указывает ли `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
. Для меня двусмысленно говорить о том, означает ли "тип объекта" его тип времени выполнения или его статический тип.
Ответы
Ответ 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.