Spec-Zone.ru › C++

Адрес перегруженной функции

Помимо выражений вызова функции, в которых выполняется разрешение перегрузки, имя перегруженной функции может встречаться в следующих 7 контекстах:

Контекст Цель
инициализатор в объявлении объекта или ссылки инициализируемый объект или ссылка
в правой части выражения присваивания левая часть присваивания
в качестве аргумента вызова функции параметр функции
в качестве аргумента пользовательского оператора параметр оператора
инструкция return возвращаемое значение функции или преобразования
явное преобразование или аргумент static_cast соответствующее преобразование
нетиповой аргумент шаблона соответствующий параметр шаблона

В каждом контексте перед именем перегруженной функции может стоять оператор взятия адреса &, а само имя может быть заключено в избыточный набор скобок.

Если целевой тип содержит тип-заполнитель, выполняется вывод типа-заполнителя, и в дальнейшем описании в качестве целевого типа используется выведенный тип.

(начиная с C++26)

Выбор функций

При взятии адреса перегруженной функции из набора перегрузки, на который ссылается имя перегруженной функции, выбирается набор S функций:

  • Если целевого типа нет, выбираются все именованные функции, не являющиеся шаблонами.
  • В противном случае функция, не являющаяся шаблоном, с типом F выбирается для типа функции FT целевого типа, если F (после возможного применения преобразования указателя на функцию)(начиная с C++17) идентичен FT.[1]
  • Специализация (если таковая имеется), полученная для каждого именованного шаблона функции в результате вывода аргументов шаблона, также добавляется в S.

Если целевой тип является типом указателя на функцию или ссылки на функцию, S может включать только функции, не являющиеся членами класса, функции-члены с явным объектом(начиная с C++23) и статические функции-члены. Если целевой тип является типом указателя на функцию-член, S может включать только функции-члены с неявным объектом.

  1. Иными словами, класс, членом которого является функция, не учитывается, если целевой тип является типом указателя на функцию-член.

Исключение функций

После формирования набора S функции исключаются в следующем порядке:

  • Из S исключаются все функции, связанные ограничения которых не удовлетворены.
(начиная с C++20)
  • Если в S остается более одной функции, все специализации шаблонов функций в S исключаются, если S также содержит функцию, не являющуюся шаблоном.
  • Данная функция, не являющаяся шаблоном, func исключается, если S содержит вторую функцию, не являющуюся шаблоном, с более строгим частичным упорядочением ограничений, чем у func.
(начиная с 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

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API