Вывод типов и свертывание ссылок в CTAD

Похоже, я не понимаю чего-то фундаментального в правилах вывода/ссылки типов C++. Скажем, у меня есть объект entity, который принимает ссылку rvalue в конструкторе и имеет элемент данных того же типа. Меня это устраивало, пока я не узнал, что выведенный тип выводится в соответствии с правилами свертывания ссылок, например:

Когда я привязываю xvalue Alloc&& к параметру Alloc&& alloc, выводимый тип Alloc будет Alloc&& в соответствии с:

  1. A& & становится A&
  2. A& && становится A&
  3. A&& & становится A&
  4. A&& && становится A&&

Итак, когда выведенный тип «Alloc» на самом деле является Alloc&& в следующем примере, почему этот класс, кажется, хранит тип значения Alloc, а не выведенную ссылку rvalue? Разве тип члена класса «Alloc» не должен быть тайно ссылкой на rvalue, поскольку я вызываю ctor с помощью xvalue (std::move)?

Демо

#include <memory>
#include <cstdio>
#include <type_traits>

template <typename Alloc>
struct entity
{
    entity(Alloc&& alloc)
        :   alloc_{ alloc }
    {}

    auto print() {
        if constexpr (std::is_rvalue_reference_v<Alloc>) {
            printf("Is type is &&");
        } else if constexpr (std::is_lvalue_reference_v<Alloc>) {
            printf("Is type is &");
        } else {
            printf("Is type value");
        }
    }

    Alloc alloc_;
};


int main()
{
    std::allocator<int> a;
    entity e(std::move(a));
    e.print();
}

Выход:

Is type value

Это два вопроса в одном: неявно сгенерированный CTAD и перенаправление ссылок. Мне кажется, вы путаетесь в обоих. Пожалуйста, спрашивайте по одному.

Passer By 14.02.2023 08:58
Alloc&& не является ссылкой на пересылку, поскольку она не используется в шаблоне функции, это просто ссылка на rvalue
Alan Birtles 14.02.2023 08:59

Свертывание ссылки происходит после вычета параметра шаблона. Они предназначены для совместной работы, но в конечном итоге являются отдельными. "выведенный тип Alloc будет Alloc&&" Что?

HolyBlackCat 14.02.2023 09:04

@HolyBlackCat Этого я не понимаю. Я думал, что типы выводятся таким образом, чтобы они соответствовали ожидаемому типу, включая ссылки, если это возможно. Я не знал, что правила для шаблонов CTAD и функций отличаются. Есть литература по этой теме?

glades 14.02.2023 09:22

Семантика перемещения C++ от Джосуттиса или его выступления на cppcon. Опубликованный код представляет то, что Джосуттис называет «шаблонной сущностью», но не шаблоном функции. Вы можете поставить лайк это, но обратите внимание на a. шаблонный конструктор б. предоставленное вручную руководство по дедукции.

alagner 14.02.2023 09:34

типы выводятся таким образом, что они совпадают..." Да, но если вы посмотрите только на сворачивающиеся правила, у вас возникнут неясности. В вашем случае Alloc = T и Alloc = T && оба дадут правильный тип параметра. Таким образом, правила дедукции имеют отдельную формулировку, которая убирает это. | Правила для неявного CTAD немного отличаются, в этом случае он не выведет Alloc = T &. — Есть какая-нибудь литература по этой теме? Просто cppreference, но не уверен, что этого будет достаточно.

HolyBlackCat 14.02.2023 10:17

@HolyBlackCat Спасибо, я думаю, что я ищу что-то вроде пошагового руководства о том, как компилятор делает то, что он делает в этом отношении. Это было бы очень полезно. Но продолжаю искать :)

glades 14.02.2023 12:06
Стоит ли изучать 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 называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
7
58
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

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

Alloc&& не является ссылкой для пересылки, так как она не используется в шаблоне функции, это просто ссылка на rvalue. Следовательно, Alloc выводится как std::allocator<int>, а alloc в вашем конструкторе является ссылкой на rvalue.

Чтобы увидеть ссылки на переадресацию, вам нужен шаблон функции. Например.:

#include <cstdio>
#include <memory>

template <typename Alloc>
void print(Alloc&& alloc)
{
    if constexpr (std::is_rvalue_reference_v<Alloc>) {
        printf("Is type is &&\n");
    } else if constexpr (std::is_lvalue_reference_v<Alloc>) {
        printf("Is type is &\n");
    } else {
        printf("Is type value\n");
    }
}

int main()
{
    print(std::allocator<int>());
    std::allocator<int> a;
    print(a);
    print(std::move(a));
}

Однако обратите внимание, что Alloc по-прежнему не будет ссылкой на rvalue, при передаче rvalue Alloc выводит std::allocator, но alloc является ссылкой на rvalue:

#include <cstdio>
#include <memory>

template <typename Alloc>
void print(Alloc&& alloc)
{
    if constexpr (std::is_rvalue_reference_v<Alloc>) {
        printf("Is type is &&\n");
    } else if constexpr (std::is_lvalue_reference_v<Alloc>) {
        printf("Is type is &\n");
    } else {
        printf("Is type value\n");
    }
    if constexpr (std::is_rvalue_reference_v<decltype(alloc)>) {
        printf("Argument is type is &&\n");
    } else if constexpr (std::is_lvalue_reference_v<decltype(alloc)>) {
        printf("Argument is type is &\n");
    } else {
        printf("Argument is type value\n");
    }
}

int main()
{
    print(std::allocator<int>());
    std::allocator<int> a;
    print(a);
    print(std::move(a));
}

Отпечатки:

Is type value
Argument is type is &&
Is type is &
Argument is type is &
Is type value
Argument is type is &&
Alloc не будет ссылкой в ​​вашей функции с std::move(a). Неявно сгенерированный CTAD будет вести себя точно так же, как и ваша функция.
Passer By 14.02.2023 09:18

@PasserBy исправлено, я знал, что не должен был писать это на своем телефоне без предварительного тестирования

Alan Birtles 14.02.2023 09:31

Спасибо, немного проясняешь ситуацию. Хотя все еще немного запутался, но я думаю, что теперь мне нужно прочитать кое-какую литературу... :)

glades 14.02.2023 09:43

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