decltype для переменной ссылочного типа с фигурными скобками

Dec 15 2020

Рассмотрим следующий код :

#include <type_traits>

int main() {
    const int& p = 42;
    auto v1 = decltype(p){};
    static_assert(std::is_same_v<decltype(v1), int>);
    
    decltype(p) v2{};
    static_assert(std::is_same_v<decltype(v2), const int&>);
    // auto v3 = X(const int&)X {};
}

Тип v1выводится как int. При этом v2ожидаемо выводится тип const int&. Я думаю, что первый шаг v1можно рассматривать как добавление еще одного псевдонима типа, using T = decltype(p);а затем auto v4 = T{};. Как это выражение ( decltype(p){}или T{}) трактуется компилятором? Я знаю, что эта {}часть предназначена для создания экземпляра, но почему результирующий тип v1не является ссылочным типом?

Еще один вопрос: есть ли способ объявить v3переменную того же типа, что и v1явно указанный тип const int&(вместо decltype(p))?

Приветствуются любые ссылки на стандарт.

Ответы

1 Enlico Dec 15 2020 at 00:48

(Тем, кто проголосовал против: если вы проголосовали против, потому что считаете, что цитирование Скотта Мейерса не эквивалентно цитированию стандарта, да ладно ...)

Как вы можете прочесть из « Эффективного современного C ++» (дополненного той частью исправлений, которую вы можете найти, Case 2:выполнив поиск по этой ссылке, и это просто упрощает чтение следующего текста, но это не существенно для вопроса):

Если ParamTypeэто не ссылка [...], если exprтип является ссылкой, игнорируйте ссылочную часть. Если [...] exprесть const, примите это тоже. Если это так volatile, также игнорируйте это.

где param- спецификатор объявления, который в вашем случае является справедливым auto, т.е. не является ссылкой.

Другими словами, вы создаете с v1помощью простого auto(не auto&), то есть путем копирования, поэтому не имеет значения, инициализируете ли вы его с помощью сущности, которая является ссылкой или нет, или даже с помощью constили нет ( volatileили нет, fwiw), потому что вы его копируете.

Подумайте о более простом случае,

int i = 3;
int& p = i;
auto v1 = p;

насколько это v1касается, это действительно не важно , является ли он initalized с одной ( i) или другой ( p) имя , под которым же известно лицо, потому что он получит копию того , что значение , которое компания имеет.

autoвывод типа работает так же, как вывод типа шаблона (за исключением разницы в том, как они работают с инициализатором в фигурных скобках, что в данном случае не имеет значения), и для обоих из них вы можете обратиться к Эффективному современному C ++ Скотта Мейерса .