диагностика и качество ошибок компиляцииdiagnostics and compiler error quality
Расширение синтаксиса удаления функций (C++11) необязательной строкой-объяснением: void old_api() = delete("use new_api() instead"); — компилятор обязан включить эту строку в диагностику при попытке вызова.An extension of function deletion syntax (C++11) with an optional explanatory string: void old_api() = delete("use new_api() instead"); — the compiler is required to surface this string in the diagnostic when the deleted function is called.
P2573 расширяет существующий синтаксис = delete; необязательным строковым литералом: void old_api() = delete("use new_api() instead — removed in v3.0");. При попытке вызвать удалённую функцию компилятор обязан вывести эту строку как часть диагностики, а не только общее сообщение вида "call to deleted function".P2573 extends the existing = delete; syntax with an optional string literal: void old_api() = delete("use new_api() instead — removed in v3.0");. When code attempts to call the deleted function, the compiler is required to surface this string as part of the diagnostic, rather than only a generic "call to deleted function" message.
void process(double) = delete;
process(3.14);
// error: use of deleted function 'void process(double)'// error: use of deleted function 'void process(double)'
// ...и всё — почему удалена, чем заменить, неизвестно// ...and that's it — why it was deleted, what to use instead, unknown
void process(double) = delete("no implicit narrowing — cast explicitly");
process(3.14);
// error: use of deleted function 'void process(double)':// error: use of deleted function 'void process(double)':
// no implicit narrowing — cast explicitly// no implicit narrowing — cast explicitly
Без объяснения вызывающий код получал сухую ошибку компилятора без контекста — приходилось идти к объявлению, читать (если повезёт) комментарий над ним или искать в истории коммитов/документации, почему функция удалена и чем её заменить.Without an explanation, calling code got a dry compiler error with no context — you had to go find the declaration, read (if you were lucky) a comment above it, or search commit history/documentation to learn why the function was deleted and what to use instead.
Намеренное устаревание или удаление перегрузки (например, чтобы предотвратить неявное опасное преобразование или заставить перейти на новый API) оставляло пользователей гадать, почему именно так и что теперь делать — жалоба на неинформативность диагностики = delete звучала давно и постоянно.Deliberately deprecating/removing an overload (e.g. to prevent a dangerous implicit conversion, or to force migration to a new API) left users guessing why, and what to do now — the complaint about = delete's unhelpful diagnostics was long-standing and recurring.
Необязательная строка, выведенная прямо в сообщении компилятора, превращает удаление в конкретное действие: пользователь узнаёт причину и — как правило — замену немедленно, вместо ухода в документацию за отдельным контекстом.The optional string, surfaced directly in the compiler's output, turns a deletion into actionable guidance: the user learns the reason and — typically — the replacement immediately, instead of leaving the editor to hunt for context elsewhere.
Синтаксис — это = delete(string-literal); вместо голого = delete;, применимый к любой удаляемой функции: обычной перегрузке, конструктору, оператору, шаблонной специализации. Строка не участвует ни в разрешении перегрузки, ни в какой-либо семантике программы — это чисто диагностический текст.The syntax is = delete(string-literal); instead of a bare = delete;, applicable to any deletable function: an ordinary overload, a constructor, an operator, a template specialization. The string plays no role in overload resolution or any program semantics — it's purely diagnostic text.
void process(int) {}
void process(double) = delete("no implicit narrowing — cast explicitly");
class Widget {
public:
Widget(const Widget&) = delete("Widget owns a unique resource — use std::move");
Widget(Widget&&) = default;
};
// комбинация с [[deprecated]] иллюстративна, но избыточна:// combining with [[deprecated]] is illustrative but redundant:
// = delete уже полностью запрещает вызов, deprecated ничего не добавляет// = delete already fully prevents the call, deprecated adds nothing
[[deprecated]] void legacy_call() = delete("removed in v3.0, use new_call() instead");
Перегрузка, удалённая специально для того, чтобы перехватить нежелательное неявное числовое сужение или преобразование указателя в bool, с объяснением опасности прямо в тексте ошибки.An overload deleted specifically to intercept an unwanted implicit numeric narrowing or pointer-to-bool conversion, with the danger explained right in the error text.
void set_flag(bool) {}
void set_flag(void*) = delete("pointer-to-bool is almost always a bug — compare to nullptr explicitly");
Класс, владеющий уникальным ресурсом, объясняет прямо в ошибке компиляции, почему копирование запрещено и что использовать вместо него — та же логика владения, что и в std::unique_ptr.A class owning a unique resource explains directly in the compile error why copying is forbidden and what to use instead — the same ownership logic as std::unique_ptr.
class FileHandle {
public:
FileHandle(const FileHandle&) = delete("FileHandle owns a unique resource — use std::move");
FileHandle& operator=(const FileHandle&) = delete("FileHandle owns a unique resource — use std::move");
FileHandle(FileHandle&&) noexcept = default;
};
Старая свободная функция удаляется с прямым указанием имени функции-замены, вместо того чтобы оставлять её работающей до неопределённого момента "когда-нибудь уберём".An old free function is deleted with a direct pointer to the replacement function's name, instead of leaving it working until some vague "we'll remove it eventually" point.
void connect_legacy(const char*) = delete("removed in v3.0, use connect(std::string_view, Options) instead");
Специализация шаблона для конкретного типа удаляется, чтобы предотвратить неправильное использование — со ссылкой на уже известную проблему этого типа, описанную в другом месте базы знаний.A template specialization for a specific type is deleted to prevent misuse — pointing to a known issue with that type documented elsewhere in this knowledge base.
template<>
void serialize<std::vector<bool>>(const std::vector<bool>&) =
delete("std::vector<bool> is not a real container — see gotcha in unordered-containers.html");
Причина не влияет ни на разрешение перегрузки, ни на какую-либо семантику программы — поведение идентично обычному = delete; во всём, кроме текста ошибки компилятора. Это не меняет, что компилируется, а только то, насколько понятно это падает.The reason has zero effect on overload resolution or any program semantics — behavior is identical to a plain = delete; in everything except the compiler's error text. It doesn't change what compiles, only how clearly it fails.
Разные компиляторы могут по-разному форматировать/встраивать строку-причину в диагностику — это implementation-defined представление, а не гарантированно одинаковый формат между GCC/Clang/MSVC. Не стоит рассчитывать на идентичную формулировку ошибки во всех тулчейнах.Different compilers may format/surface the reason string differently in their diagnostics — this is implementation-defined presentation, not a guaranteed identical format across GCC/Clang/MSVC. Don't assume identical error message wording across toolchains.
Удалённая функция (с причиной или без) по-прежнему может быть ВЫБРАНА как лучшее совпадение (что и вызывает ошибку удаления) — она не невидима для компилятора так, будто объявления вовсе не существует. В этом и смысл: поймать конкретную ошибку и объяснить её, а не сделать вид, что перегрузки нет — распространённое заблуждение в обратную сторону.A deleted function (with or without a reason) can still be SELECTED as the best match (which is what triggers the deletion error) — it isn't invisible to the compiler the way removing the declaration entirely would be. That's the whole point: to catch the specific mistake and explain it, not to make the overload disappear — a common misunderstanding in the opposite direction.