Адрес перегруженной функции
Помимо выражений вызова функции, в которых выполняется разрешение перегрузки, имя перегруженной функции может встречаться в следующих 7 контекстах:
| Контекст | Цель |
|---|---|
| инициализатор в объявлении объекта или ссылки | инициализируемый объект или ссылка |
| в правой части выражения присваивания | левая часть присваивания |
| в качестве аргумента вызова функции | параметр функции |
| в качестве аргумента пользовательского оператора | параметр оператора |
инструкция return | возвращаемое значение функции или преобразования |
явное преобразование или аргумент static_cast | соответствующее преобразование |
| нетиповой аргумент шаблона | соответствующий параметр шаблона |
В каждом контексте перед именем перегруженной функции может стоять оператор взятия адреса &, а само имя может быть заключено в избыточный набор скобок.
| Если целевой тип содержит тип-заполнитель, выполняется вывод типа-заполнителя, и в дальнейшем описании в качестве целевого типа используется выведенный тип. | (начиная с C++26) |
Выбор функций
При взятии адреса перегруженной функции из набора перегрузки, на который ссылается имя перегруженной функции, выбирается набор S функций:
- Если целевого типа нет, выбираются все именованные функции, не являющиеся шаблонами.
- В противном случае функция, не являющаяся шаблоном, с типом
Fвыбирается для типа функцииFTцелевого типа, еслиF(после возможного применения преобразования указателя на функцию)(начиная с C++17) идентиченFT.[1] - Специализация (если таковая имеется), полученная для каждого именованного шаблона функции в результате вывода аргументов шаблона, также добавляется в
S.
Если целевой тип является типом указателя на функцию или ссылки на функцию, S может включать только функции, не являющиеся членами класса, функции-члены с явным объектом(начиная с C++23) и статические функции-члены. Если целевой тип является типом указателя на функцию-член, S может включать только функции-члены с неявным объектом.
- Иными словами, класс, членом которого является функция, не учитывается, если целевой тип является типом указателя на функцию-член.
Исключение функций
После формирования набора S функции исключаются в следующем порядке:
| (начиная с C++20) |
- Если в
Sостается более одной функции, все специализации шаблонов функций вSисключаются, еслиSтакже содержит функцию, не являющуюся шаблоном.
| (начиная с C++20) |
- Данная специализация шаблона функции
specисключается, еслиSсодержит вторую специализацию шаблона функции, шаблон функции которой более специализирован, чем шаблон функции уspec.
После таких исключений (если они были) в S должна остаться ровно одна выбранная функция. В противном случае программа некорректна.
Пример
int f(int) { return 1; }
int f(double) { return 2; }
void g(int(&f1)(int), int(*f2)(double)) { f1(0); f2(0.0); }
template<int(*F)(int)>
struct Templ {};
struct Foo
{
int mf(int) { return 3; }
int mf(double) { return 4; }
};
struct Emp
{
void operator<<(int (*)(double)) {}
};
int main()
{
// 1. initialization
int (*pf)(double) = f; // selects int f(double)
int (&rf)(int) = f; // selects int f(int)
int (Foo::*mpf)(int) = &Foo::mf; // selects int mf(int)
// 2. assignment
pf = nullptr;
pf = &f; // selects int f(double)
// 3. function argument
g(f, f); // selects int f(int) for the 1st argument
// and int f(double) for the second
// 4. user-defined operator
Emp{} << f; //selects int f(double)
// 5. return value
auto foo = []() -> int (*)(int)
{
return f; // selects int f(int)
};
// 6. cast
auto p = static_cast<int(*)(int)>(f); // selects int f(int)
// 7. template argument
Templ<f> t; // selects int f(int)
// prevent “unused variable” warnings as if by [[maybe_unused]]
[](...){}(pf, rf, mpf, foo, p, t);
}
Отчеты об ошибках
Следующие отчеты об ошибках, изменяющие поведение, были ретроактивно применены к ранее опубликованным стандартам C++.
| DR | Применимо к | Опубликованное поведение | Правильное поведение |
|---|---|---|---|
| CWG 202 | C++98 | нетиповой аргумент шаблона не считался контекстом взятия адреса перегруженной функции | считается |
| CWG 250 | C++98 | специализации шаблонов функций, полученные с недедуцируемыми аргументами шаблона, не выбирались из набора перегрузки | также выбираются |
| CWG 1153 | C++98 | было неясно, соответствует ли заданный тип функции целевому типу | прояснено |
| CWG 1563 | C++11 | было неясно, является ли списочная инициализация контекстом взятия адреса перегруженной функции | прояснено |
Ссылки
- Стандарт C++23 (ISO/IEC 14882:2024):
- 12.3 Адрес перегруженной функции [over.over]
- Стандарт C++20 (ISO/IEC 14882:2020):
- 12.5 Адрес перегруженной функции [over.over]
- Стандарт C++17 (ISO/IEC 14882:2017):
- 16.4 Адрес перегруженной функции [over.over]
- Стандарт C++14 (ISO/IEC 14882:2014):
- 13.4 Адрес перегруженной функции [over.over]
- Стандарт C++11 (ISO/IEC 14882:2011):
- 13.4 Адрес перегруженной функции [over.over]
- Стандарт C++98 (ISO/IEC 14882:1998):
- 13.4 Адрес перегруженной функции [over.over]
© cppreference.com
Licensed under the Creative Commons Attribution-ShareAlike Unported License v3.0.
https://en.cppreference.com/cpp/language/overloaded_address