Почему атрибуты const в аргументах функции используются для перегрузки разрешения?
Возможный дубликат:
Функции с аргументами const и перегрузкой
Меня довольно путают правила перегрузки и объявления const.
Вот две вещи, которые меня озадачивают, может быть, вы можете помочь мне найти более глубокое недоразумение в моей голове, что приводит к тому, что они озадачивают меня.;)
Первый выпуск:
Мой компилятор позволяет это:
void f(int & x) {
std::cout << "plain f" << std::endl;
}
void f(const int & x) {
std::cout << "const f" << std::endl;
}
Но следующее приводит к ошибке компиляции (функция уже имеет тело):
void f(int x) {
std::cout << "plain f" << std::endl;
}
void f(const int x) {
std::cout << "const f" << std::endl;
}
Я думаю, что это имеет смысл, потому что я думал, что const был только там, чтобы сообщить компилятору, что передаваемый объект не изменяется, а во втором случае он все равно копируется. Но если это правильно, то почему я могу перегружать функции, используя const?
Другими словами, почему, если я использую компиляционную версию и вызываю такие функции, как это:
int x1 = 5;
const int x2 = 5;
f(x1);
f(x2);
Я получаю "plain f" и "const f" вместо "const f" дважды? По-видимому, теперь я также использую const, чтобы сообщить компилятору, что функция вызывает не только то, что ссылка не изменяется. Это становится более запутанным, потому что, если я удалю "обычную" версию, она будет работать нормально и дважды вызовет версию "const".
Теперь, каков мой реальный вопрос? Я хотел бы знать, каковы идеи, лежащие в основе этого поведения, потому что в противном случае его запоминание очень сложно.
Ответы
Ответ 1
Я думал, что const был только там, чтобы сообщить компилятору, что объект, являющийся не изменен, и во втором случае он все равно скопирован
Вы правы. Поскольку во втором случае он все равно копируется, и поэтому const
не имеет никакого отношения к вызывающему, стандарт определяет, что void f(const int x)
и void f(int x)
имеют одну и ту же подпись. Следовательно, они сталкиваются, вы пытаетесь определить одну и ту же функцию дважды.
Так как в первом случае он не копируется в любом случае, void f(const int &x)
и void f(int &x)
имеют разные подписи. Поэтому они перегружаются.
В вашем первом случае запрещается вызывать int&
версию f
с x2
как аргумент, потому что это создаст неконстантную ссылку на объект const без какого-либо явного приведения в действие. Выполняя это, мы побеждаем цель системы const (которая заключается в том, что если вы хотите разрушить const-безопасность, вы должны сделать это явно с помощью cast). Поэтому имеет смысл иметь const- и non-const перегрузки функций со справочными параметрами.
В вашем втором случае нет никакой связи между константой источника копии и константой адресата. Вы можете инициализировать константную переменную из неконстантной или неконстантной из константы. Это не вызывает проблем и не нарушает безопасность. Вот почему стандарт помогает сделать это понятным, указав, что ваши две "разные" версии f
на самом деле являются одной и той же функцией.
Ответ 2
n3337 13.1
[Примечание: как указано в 8.3.5, объявления функций, которые имеют эквивалентные объявления параметров объявляют одну и ту же функцию и поэтому не может быть перегружен: ffer только в присутствии или отсутствии
- объявления параметров, которые di3 константы и/или летучих являются эквивалентными. То есть константа и изменчивые типы-спецификаторы для каждого типа параметров игнорируются, когда определяя, какая функция объявляется, определяется или вызывается. [ Пример:
typedef const int cInt;
int f(int);
int f(const int); // redeclaration of f(int)
int f(int) { /* ... */ } // definition of f(int)
int f(cInt) { /* ... */ } // error: redefinition of f(int)
- конец пример] Только константные и неустойчивые типы-спецификаторы в самом внешнем уровень характеристики типа параметра игнорируется в этом мода; const и volatile-спецификаторы, закопанные внутри параметра тип спецификации являются значительными и могут использоваться для различения перегруженных функций .124 В частности, для любого типа T, "указатель на T", "указатель на const T" и "указатель на volatile T" - рассмотрены различные типы параметров, как "ссылка на T", "ссылка на const T" и "ссылка на volatile T".