Явные удаленные конструкторы – имеет ли это значение?

При пометке конструктора как удаленного, т.е.

class MyClass {

   // ... 

   MyClass(int x) = delete;

   // ... 

};

есть ли какой-либо эффект от маркировки удаленного конструктора как explicit? то есть

   explicit MyClass(int x) = delete;

?

Может быть, с точки зрения отчета об ошибках? explicit может выдать другую ошибку при неявном использовании конструктора и при явном его использовании.

NathanOliver 26.07.2024 18:48

Сообщается о другой ошибке: godbolt.org/z/KojesT71d попытка использовать удаленную функцию или отсутствующее преобразование. Возможно, произойдет что-то более интересное, если будет больше перегрузок конструктора или функции, принимающей сконструированный класс.

Marek R 26.07.2024 18:52

Другая ортогональная ситуация: компилятор может выдать другое предупреждение в зависимости от того, является ли этот удаленный конструктор (явный или неявный) public: или нет. Некоторые предупреждения могут оказаться более озадачивающими, чем другие, для программиста, попавшего в ситуацию.

Eljay 27.07.2024 15:54

@Eljay: Я всегда публикую удаления, но полагаю, что это тоже может быть вопросом предпочтений.

einpoklum 27.07.2024 17:33
Стоит ли изучать 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
4
93
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

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

Да, = delete не влияет на разрешение перегрузки, за исключением того, что если в конечном итоге разрешение перегрузки выберет удаленную перегрузку, то разрешение перегрузки будет считаться неправильно сформированным. = delete не изменяет процесс принятия решений по разрешению перегрузки.

explicit существенно влияет на разрешение перегрузки, поскольку от него зависит, будет ли конструктор участвовать в качестве кандидата в различных сценариях разрешения перегрузки.

Обе конструкции ортогональны. Одно не означает, что следует добавить или исключить другое.


Пример:

struct MyClass {
    MyClass(int x) = delete;
    MyClass(long x) { };
};

Без explicit в первом конструкторе MyClass x = 0; имеет неверный формат, поскольку разрешение перегрузки предпочтет первый конструктор. При использовании explicit первый конструктор не учитывается при инициализации копирования, а выбирается второй (который в противном случае был бы худшим совпадением). Инициализация не будет неправильной.

С другой стороны, при инициализации формы MyClass x(0);, которая является прямой инициализацией, всегда учитываются все конструкторы, и при разрешении перегрузки выбирается первый, независимо от того, является ли он explicit или нет. Поэтому эта инициализация всегда будет неправильной.

Итак, в этом примере вам нужно решить, хотите ли вы выполнить только явное преобразование из int неправильного формата (при этом разрешая неявное и явное преобразование из long) или хотите ли вы выполнить неявное и явное преобразование из long неправильного формата.


Даже если это единственный конструктор класса, разница все равно есть.

Предположим, существует набор перегрузок функций

void f(MyClass);
void f(A);

с

struct MyClass {
    explicit MyClass(int x) = delete;
};

struct A {
    A(int x) {};
};

Тогда попытка вызвать f(0) является корректной, поскольку первая перегрузка нежизнеспособна. explicit конструкторы не учитываются для неявных последовательностей преобразования аргументов функции при разрешении перегрузки. Только вторая перегрузка является жизнеспособной и будет выбрана.

Но если explicit нет, то обе перегрузки становятся жизнеспособными и разрешение перегрузки будет неоднозначным. То, что конструктор удален, не имеет значения для этого определения.


Удаление конструктора означает, что вы хотите, чтобы конкретный результат разрешения перегрузки привел к неправильному форматированию инициализации. Принимая решение, какую форму вы хотите сделать неправильной, вы всегда должны учитывать, следует ли применять explicit, точно так же, как при определении неудаляемых перегрузок.

@einpoklum Я уточнил. Я не хочу только сказать, что это не влияет на то, является ли конструктор кандидатом, я хочу сказать, что это вообще не влияет на разрешение перегрузки (за исключением того, что разрешение перегрузки будет неправильно сформировано, если удаленный конструктор будет выбрано).

user17732522 26.07.2024 21:10

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