Влияние автоматических конструкторов, удаленных пользователем, на неявное создание конструкторов копирования

Как автоконструкторы, удаленные пользователем, влияют на неявное создание конструкторов копирования? Например:

struct Foo {
    Foo(X) = delete;
    auto operator=(X) = delete;
};

int main() {
    Foo a;
    Foo b(a);
    b = a;
}

В приведенной выше структуре, если X равно auto, const auto& или const auto&&, компилятор по-прежнему генерирует конструктор копирования и оператор присваивания копии, и, следовательно, код компилируется и выполняется полностью нормально.

Но если X равно auto& или auto&&, то компилятор не будет генерировать конструктор копирования и оператор присваивания копии, и я получаю сообщение об ошибке «использование удаленной функции».

Я пробовал в GCC, Clang и ICC (к сожалению, MSVC все еще не поддерживает автоматические параметры), и во всех трех наблюдается одинаковое поведение. Так что, я думаю, это где-то определено в стандарте.

Какое стандартное правило определяет вышеупомянутое поведение компиляторов?

Конструктор, который использует auto (является шаблоном), никогда не является конструктором копирования или перемещения.

NathanOliver 20.02.2023 18:42

В любом случае мы можем получить минимальный воспроизводимый пример кода, с которым вы хотите работать, но не работает? Скорее всего, вы сталкиваетесь со случаем, когда auto& предпочтительнее, потому что вы пытаетесь скопировать неконстантное lvalue.

NathanOliver 20.02.2023 18:44

Кстати, msvc поддерживает автоматические параметры, но только с С++ 20 (как и должно быть) godbolt.org/z/Gnjr7sPse

463035818_is_not_a_number 20.02.2023 19:36

@NathanOliver извините, я обновил вопрос с минимальным воспроизводимым примером.

Sourav Kannantha B 20.02.2023 20:50

В вашем примере вы передаете не-const lvalue при построении b (как догадался @NathanOliver). auto& и auto&& (=> Foo&) лучше совпадают, чем const Foo&, поскольку не требуют преобразования.

Ted Lyngmo 20.02.2023 21:55
Стоит ли изучать 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 называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
3
5
56
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

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

auto в параметре функции означает то же самое, что и замена его параметром шаблона.

Так, например.

Foo(auto&) = delete;

такой же как

template <typename T>
Foo(T&) = delete;

Шаблонные конструкторы никогда не являются конструкторами копирования/перемещения, а шаблонные операторы присваивания никогда не являются операторами присваивания копирования/перемещения.

Таким образом, они вообще не влияют на генерацию неявных конструкторов копирования/перемещения/операторов присваивания. Независимо от того, используете ли вы auto, const auto&, auto&, const auto&& или auto&&. Неявный конструктор копирования и перемещения и операторы присваивания по-прежнему будут генерироваться.

Однако объявленные пользователем шаблонные перегрузки по-прежнему участвуют в разрешении перегрузок и в определенных ситуациях могут быть выбраны вместо неявно объявленных в соответствии с обычными правилами разрешения перегрузок.

Я обновил вопрос с минимальным воспроизводимым примером. Посмотрите, не связана ли ошибка, которую я получаю, с правилами разрешения перегрузки.

Sourav Kannantha B 20.02.2023 20:52

@SouravKannanthaB Это так, потому что auto&/auto&&, выведенное из Foo&, лучше соответствует, чем const Foo& из неявных перегрузок для не-const lvalue типа Foo (a). Для const auto& и const auto&& оба одинаково хороши, поэтому предпочтительнее нешаблонный. В случае только auto существует специальное правило, согласно которому специализация шаблона конструктора, которая сама принимает один аргумент типа класса (cv-qualified), никогда не будет рассматриваться (потому что это всегда будет бесконечная рекурсия).

user17732522 21.02.2023 07:53

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

Можете ли вы разработать конструктор, разрешающий `Class c(std::move(another_class))`, когда класс имеет член типа const std::unique_ptr?
Конструктор преобразования странным образом не конкурирует с конструктором копирования
Скопируйте отличие конструктора для std::unique_ptr
Конструктор копирования выдает ошибку нулевого значения в C++
Почему оператор = и конструктор копирования обрабатываются по-разному в виртуальном наследовании?
Мой класс не имеет подходящего конструктора копирования - в зависимости от того, является ли аргумент конструктора константным или нет
Почему при вставке() в std::map дважды вызывается копирующий конструктор?
Почему вызывается конструктор копирования объекта, который используется для инициализации другого объекта?
Почему std::vector копирует конструкцию вместо конструкции перемещения, когда деструктор может выбросить?
Разве здесь не должно быть вызова копировального центра? Elision отключен (без оптимизации именованного возвращаемого значения)