позволяют использовать эти две функции одновременно как различную функцию, так как они действительно отличаются от того, «может ли параметр быть написан или нет». Интуитивно это должно быть!
blockquote>Перегрузка функций основана на параметрах, предоставляемых вызывающим. Здесь верно, что вызывающий может предоставить значение
const
или неconst
, но по логике он не должен иметь никакого значения для функциональности, предоставляемой вызываемой функцией. Рассмотрим:f(3); int x = 1 + 2; f(x);
Если
f()
делает разные вещи в каждой из этих ситуаций, это будет очень запутанным! Программист этого кода, вызывающийf()
, может иметь разумное ожидание одинакового поведения, свободно добавляя или удаляя переменные, которые передают параметры без его недействительности программы. Это безопасное, разумное поведение является отправной точкой, которую вы хотели бы оправдать исключениями, и действительно есть одно поведение может варьироваться , когда перегруженная функция ala:void f(const int&) { ... } void f(int&) { ... }
Итак, я думаю, это то, что вы находите неинтуитивным: что C ++ обеспечивает более «безопасность» (принудительное согласованное поведение посредством поддержки только одной реализации) для не-ссылок, чем ссылки.
Причины Я могу подумать:
- Поэтому, когда программист знает, что параметр non
const&
будет иметь более длительный срок службы, они могут выбрать оптимальную реализацию. Например, в приведенном ниже коде может быть быстрее вернуть ссылку на членT
вF
, но еслиF
является временным (что может быть, если компилятор соответствуетconst F&
), то a - требуется возврат значения. Это все еще довольно опасно, так как вызывающий должен знать, что возвращаемая ссылка действительна только в том случае, если параметр находится вокруг.T f(const F&); T& f(F&); // return type could be by const& if more appropriate
- распространение таких классификаторов, как
const
(f16)Здесь некоторые (предположительно
F
member-) переменная типаT
экспонируются какconst
или не-const
на основеconst
-значения параметра при вызовеf()
. Этот тип интерфейса может быть выбран, если вы хотите расширить класс с помощью нечленов-функций (чтобы сохранить минимальный класс или при написании шаблонов / algos, используемых на многих классах), но идея аналогична функцииconst
-члена, напримерvector::operator[]()
, где вы хотите, чтобыv[0] = 3
разрешался на векторе неconst
, но не наconst
.Когда значения принимаются по значению, они выходят за пределы области при возврате функции, поэтому нет действительного сценария, связанного с возвратом ссылки на часть параметра и желанием распространить его квалификаторы.
Взлом поведения, которое вы хотите
Учитывая правила ссылок, вы можете использовать их для получите нужное поведение - вам просто нужно быть осторожным, чтобы случайно изменить параметр «не-константа-ссылка», поэтому для неконстантных параметров может потребоваться следующая практика:
T f(F& x_ref) { F x = x_ref; // or const F is you won't modify it ...use x for safety... }
Последствия перекомпиляции
Не говоря уже о том, почему язык запрещает перегрузку на основе
const
параметр по значению, возникает вопрос, почему он не настаивает на согласованностиconst
-ness в декларации и определении.Для
f(const int)
/f(int)
... если вы объявляют функцию в файле заголовка, тогда лучше не включать квалификаторconst
, даже если последующее определение в файле реализации будет иметь его. Это связано с тем, что во время обслуживания программист может захотеть удалить квалификатор ... удаление его из заголовка может вызвать бессмысленную перекомпиляцию клиентского кода, поэтому лучше не настаивать на том, чтобы они хранились в синхронизации, - и действительно, поэтому компилятор не делает этого, t создает ошибку, если они отличаются. Если вы просто добавили или удалилиconst
в определении функции, то это близко к реализации, где читатель кода может заботиться о константе при анализе поведения функции. Если у вас естьconst
как в заголовке, так и в файле реализации, тогда программист хочет сделать его неconst
и забывает или решает не обновлять заголовок, чтобы избежать перекомпиляции клиента, тогда он более опасен, чем другой способ вокруг, как это возможно, программист будет иметь версиюconst
из заголовка в виду, пытаясь проанализировать текущий код реализации, приводящий к неправильным рассуждениям о поведении функции. Это все очень проблема тонкой поддержки - это действительно актуально для коммерческого программирования, но в основе этого лежит руководство не использоватьconst
в интерфейсе. Кроме того, это более кратким, чтобы опустить его из интерфейса, что лучше для программистов-клиентов, читающих ваш API.