Address of an overloaded function
Помимо вызовов функций , где происходит разрешение перегрузки , имя перегруженной функции может появляться в следующих 7 контекстах:
| # | Контекст | Цель |
|---|---|---|
| 1 | инициализатор в объявлении объекта или ссылки | инициализируемый объект или ссылка |
| 2 | в правой части встроенного выражения присваивания | левая часть встроенного присваивания |
| 3 | как аргумент вызова функции | параметр функции |
| 4 | как аргумент пользовательского оператора | параметр оператора |
| 5 |
оператор
return
|
возвращаемое значение функции или преобразования |
| 6 |
аргумент
явного приведения
или
static_cast
|
соответствующее приведение |
| 7 | константный аргумент шаблона | соответствующий параметр шаблона |
В каждом контексте имя перегруженной функции может предваряться оператором взятия адреса
&
и может быть заключено в избыточный набор круглых скобок.
|
Если целевой тип содержит тип-заполнитель , выполняется выведение типа-заполнителя, и следующее описание использует выведенный тип в качестве целевого типа. |
(since C++26) |
Содержание |
Выбор функций
Когда берётся адрес перегруженной функции, из набора перегрузок, на который ссылается имя перегруженной функции, выбирается множество
S
функций:
- Если нет целевого объекта, выбираются все именованные нешаблонные функции.
-
В противном случае нешаблонная функция с типом
Fвыбирается для функционального типаFTцелевого типа, еслиF(после возможного применения преобразования указателя на функцию ) (since C++17) идентиченFT. [1] -
Специализация (если есть), сгенерированная с помощью
вывода аргументов шаблона
для каждой именованной шаблонной функции, также добавляется в
S.
Если целевой объект имеет тип указателя на функцию или ссылки на функцию,
S
может включать только нечленные функции
, явные объектные функции-члены
(начиная с C++23)
и статические функции-члены. Если целевой объект имеет тип указателя на функцию-член,
S
может включать только неявные объектные функции-члены.
- ↑ Другими словами, класс, членом которого является функция, игнорируется, если целевой тип является типом указателя-на-функцию-член.
Устранение функций
После формирования множества
S
, функции исключаются в следующем порядке:
|
(since C++20) |
-
Если более одной функции в
Sостаётся, все специализации шаблонов функций вSисключаются, еслиSтакже содержит нешаблонную функцию.
|
(since 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. инициализация int (*pf)(double) = f; // выбирает int f(double) int (&rf)(int) = f; // выбирает int f(int) int (Foo::*mpf)(int) = &Foo::mf; // выбирает int mf(int) // 2. присваивание pf = nullptr; pf = &f; // выбирает int f(double) // 3. аргумент функции g(f, f); // выбирает int f(int) для первого аргумента // и int f(double) для второго // 4. пользовательский оператор Emp{} << f; // выбирает int f(double) // 5. возвращаемое значение auto foo = []() -> int (*)(int) { return f; // выбирает int f(int) }; // 6. приведение типа auto p = static_cast<int(*)(int)>(f); // выбирает int f(int) // 7. аргумент шаблона Templ<f> t; // выбирает int f(int) // предотвращение предупреждений "неиспользуемая переменная" как с помощью [[maybe_unused]] [](...){}(pf, rf, mpf, foo, p, t); }
Отчеты о дефектах
Следующие отчеты об изменениях поведения, влияющие на дефекты, были применены задним числом к ранее опубликованным стандартам C++.
| DR | Applied to | Behavior as published | Correct behavior |
|---|---|---|---|
| CWG 202 | C++98 |
constant template argument was not a context
of taking the address of an overloaded function |
it is |
| CWG 250 | C++98 |
function template specializations generated with non-deduced
template arguments were not selected from the overload set |
also selected |
| CWG 1153 | C++98 | it was unclear whether a given function type matches the target type | made clear |
| CWG 1563 | C++11 |
it was unclear whether list-initialization is a context
of taking the address of an overloaded function |
made clear |
Ссылки
- Стандарт 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]