Почему в C ++ 11 функции " delete
d" участвуют в разрешении перегрузки ?
Почему это полезно? Или, другими словами, почему они скрыты, а не полностью удалены?
87
Почему в C ++ 11 функции " delete
d" участвуют в разрешении перегрузки ?
Почему это полезно? Или, другими словами, почему они скрыты, а не полностью удалены?
Ответы:
Половина цели
= delete
синтаксиса состоит в том, чтобы запретить людям вызывать определенные функции с определенными параметрами. В основном это делается для предотвращения неявных преобразований в определенных конкретных сценариях. Чтобы запретить конкретную перегрузку, она должна участвовать в разрешении перегрузки.Приведенный вами ответ дает вам прекрасный пример:
struct onlydouble { onlydouble(std::intmax_t) = delete; onlydouble(double); };
Если
delete
удалить функцию полностью, это сделает= delete
синтаксис эквивалентным следующему:struct onlydouble2 { onlydouble2(double); };
Вы могли сделать это:
onlydouble2 val(20);
Это законный C ++. Компилятор просматривает все конструкторы; ни один из них напрямую не принимает целочисленный тип. Но один из них может принять это после неявного преобразования. Так это назовем.
onlydouble val(20);
Это не законный C ++. Компилятор просмотрит все конструкторы, включая
delete
d. Он увидит точное совпадение черезstd::intmax_t
(которое будет точно соответствовать любому целочисленному литералу). Таким образом, компилятор выберет его, а затем немедленно выдаст ошибку, потому что он выбрал функциюdelete
d.= delete
означает «Я запрещаю это», а не просто «Этого не существует». Это гораздо более сильное заявление.Это потому, что нам не нужна специальная грамматика, чтобы сказать «этого не существует». Мы получаем это неявно, просто не объявляя конкретное рассматриваемое «this». «Я запрещаю это» представляет собой конструкцию, которая не может быть достигнута без специальной грамматики. Итак, у нас есть специальная грамматика, чтобы сказать: «Я запрещаю это», а не что-то другое.
Единственная функциональность, которую вы получили бы при наличии явной грамматики «это не существует», - это предотвращение того, чтобы кто-то позже объявил ее существованием. И этого недостаточно, чтобы нужна была собственная грамматика.
Конструктор копирования - это специальная функция-член. У каждого класса всегда есть конструктор копирования. Так же, как у них всегда есть оператор присваивания копии, конструктор перемещения и т. Д.
Эти функции существуют; вопрос только в том, законно ли им звонить. Если вы попытаетесь сказать, что это
= delete
означает, что они не существуют, тогда спецификация должна будет объяснить, что означает отсутствие функции. Это не та концепция, которую описывает спецификация.Если вы попытаетесь вызвать функцию, которая еще не была объявлена / определена, компилятор выдаст ошибку. Но это приведет к ошибке из-за неопределенного идентификатора , а не из-за ошибки «функция не существует» (даже если ваш компилятор сообщает об этом таким образом). Все различные конструкторы вызываются разрешением перегрузки, поэтому их «существование» обрабатывается в этом отношении.
В каждом случае существует либо функция, объявленная через идентификатор, либо конструктор / деструктор (также объявленный через идентификатор, просто идентификатор типа). Перегрузка оператора скрывает идентификатор за синтаксическим сахаром, но он все еще существует.
Спецификация C ++ не может обрабатывать концепцию «несуществующей функции». Он может справиться с несоответствием перегрузки. Он может справиться с неоднозначностью перегрузки. Но он не знает о том, чего там нет. Так
= delete
определяется в терминах гораздо более полезных «попыток назвать это неудачей», чем менее полезных «притвориться, что я никогда не писал эту строку».И снова перечитайте первую часть. Вы не можете этого сделать с «функции не существует». Это еще одна причина, по которой он определен таким образом: потому что один из основных вариантов использования
= delete
синтаксиса - это возможность заставить пользователя использовать определенные типы параметров, явное приведение и т. Д. В основном, чтобы помешать неявному преобразованию типов.Ваше предложение этого не сделает.
источник
= delete
иметь в виду «этот элемент не существует», что означало бы, что он не мог участвовать в разрешении перегрузки.= delete
имелось в виду «этот член не существует», то первый опубликованный мной пример не смог бы помешать людям передавать целые числа вonlydouble
конструктор , посколькуonlydouble
удаляемая перегрузка не существует . Он не будет участвовать в разрешении перегрузки и, следовательно, не помешает вам передавать целые числа. Это половина= delete
синтаксиса: возможность сказать: «Вы не можете неявно передать X этой функции».=delete
? В конце концов, мы можем сказать «не копируемый», сделав то же самое: объявив конструктор / присваивание копии закрытым. Также обратите внимание, что объявление чего-то частного не делает его невозможным для вызова; код внутри класса все еще может его вызывать. Так что это не то же самое= delete
. Нет,= delete
синтаксис позволяет нам делать то, что раньше было крайне неудобно и непостижимо, гораздо более очевидным и разумным способом.Рабочий проект C ++ 2012-11-02 не дает обоснования этого правила, а лишь несколько примеров.
struct onlydouble { onlydouble() = delete; // OK, but redundant onlydouble(std::intmax_t) = delete; onlydouble(double); };
struct sometype { void *operator new(std::size_t) = delete; void *operator new[](std::size_t) = delete; }; sometype *p = new sometype; // error, deleted class operator new sometype *q = new sometype[3]; // error, deleted class operator new[]
struct moveonly { moveonly() = default; moveonly(const moveonly&) = delete; moveonly(moveonly&&) = default; moveonly& operator=(const moveonly&) = delete; moveonly& operator=(moveonly&&) = default; ~moveonly() = default; }; moveonly *p; moveonly q(*p); // error, deleted copy constructor
источник