Decltype на переменную ссылочного типа с фигурными скобками

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

#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))?

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

Сначала не мог поверить, что decltype(p){} компилируется. По-видимому, значение {} инициализирует временное значение int, которое затем привязывается к ссылке. Хм!

HolyBlackCat 14.12.2020 18:53

Еще один вопрос 1 вопрос на вопрос плз

Language Lawyer 14.12.2020 19:05

const auto& v3 = (const int&){}; отвечает на ваш Yet another question: is there a way to declare v3...??

KamilCuk 14.12.2020 19:37

@KamilCuk хм... Я проверил clang, и он не компилируется. Работает в gcc.

αλεχολυτ 14.12.2020 19:43

@αλεχολυτ, что отличает этот синтаксис (const auto& v3 = (const int&){};) от const int& v3{};? Я имею в виду, для чего вам нужен этот синтаксис?

Enlico 14.12.2020 19:57

@Enlico, я просто хотел узнать, как воспроизвести decltype(p){} без decltype.

αλεχολυτ 15.12.2020 09:46
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
2
7
256
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

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

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

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

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

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

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

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

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

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

auto v4 = T{};. Как компилятор обрабатывает это выражение (decltype(p){} или T{})? Я знаю, что часть {} предназначена для создания экземпляров, но почему тип результата не является ссылочным?

Результат decltype(p){} является ссылочным типом. Использование auto приводит к удалению const и квалификаторов ссылок. Вывод типа объясняется здесь, и они такие же, как те, которые используются для вывода типа шаблона. Вместо этого вы можете использовать decltype(auto), чтобы сохранить эти квалификаторы (или, в этом конкретном случае, вы можете использовать const auto&).

Также выпадает volatile, если есть, как я объяснил в своем ответе.

Enlico 14.12.2020 19:10

Другие вопросы по теме