16 Overloading [over]

16.1 Overloadable declarations [over.load]

Не все объявления функций могут быть перегружены. Здесь указаны те, которые нельзя перегрузить. Программа плохо сформирована, если она содержит два таких неперегружаемых объявления в одной и той же области видимости. [ Note: Это ограничение применяется к явным объявлениям в области видимости, а также между такими объявлениями и объявлениями, сделанными через using-declaration. Это не относится к наборам функций, созданным в результате поиска имени (например, из-за using-directives) или разрешения перегрузки (например, для операторских функций). ]end note

Некоторые объявления функций не могут быть перегружены:

  • Объявления функций, которые различаются только типом возвращаемого значения, exception specificationили и тем , и другим, не могут быть перегружены.

  • Объявления функций-членов с тем же именем и одинаковыми именами parameter-type-list не могут быть перегружены, если любое из них является static объявлением функции-члена ([class.static]). Точно так же объявления шаблонов функций-членов с тем же именем, одним и тем же списком типов-параметров и одними и теми же списками параметров шаблона не могут быть перегружены, если какое-либо из них является static объявлением шаблона функции-члена. Типы неявных параметров объекта, созданных для функций-членов с целью разрешения перегрузки ([over.match.funcs]), не учитываются при сравнении списков типов параметров для применения этого правила. Напротив, если нет static объявления функции-члена среди набора объявлений функций-членов с тем же именем и одним и тем же списком типов-параметров, то эти объявления функций-членов могут быть перегружены, если они различаются по типу параметра неявного объекта. [ Example: Следующее иллюстрирует это различие:

    class X {
      static void f();
      void f();                     // ill-formed
      void f() const;               // ill-formed
      void f() const volatile;      // ill-formed
      void g();
      void g() const;               // OK: no static g
      void g() const volatile;      // OK: no static g
    };

    end example]

  • Объявления функций-членов с тем же именем иparameter-type-list такими же, а также объявления шаблонов функций-членов с тем же именем, одним и тем же списком типов-параметров и одними и теми же списками параметров шаблона не могут быть перегружены, если любой из них, но не все, имеет ref-qualifier([dcl.fct]). [Example:

    class Y {
      void h() &;
      void h() const &;             // OK
      void h() &&;                  // OK, all declarations have a ref-qualifier
      void i() &;
      void i() const;               // ill-formed, prior declaration of i
                                    // has a ref-qualifier
    };

    end example]

[ Note: Как указано в [dcl.fct], объявления функций с эквивалентными объявлениями параметров объявляют одну и ту же функцию и поэтому не могут быть перегружены:

  • Объявления параметров, которые отличаются только использованием эквивалентных typedef «типов», эквивалентны. A typedef - это не отдельный тип, а только синоним другого типа ([dcl.typedef]). [Example:

    typedef int Int;
    
    void f(int i);
    void f(Int i);                  // OK: redeclaration of f(int)
    void f(int i) { /* ... */ }
    void f(Int i) { /* ... */ }     // error: redefinition of f(int)
    

    end example]

    С другой стороны, перечисления относятся к разным типам и могут использоваться для различения объявлений перегруженных функций. [Example:

    enum E { a };
    
    void f(int i) { /* ... */ }
    void f(E i)   { /* ... */ }

    end example]

  • Объявления параметров, которые отличаются только указателем * от массива [] , эквивалентны. То есть объявление массива корректируется, чтобы стать объявлением указателя ([dcl.fct]). Только второе и последующие измерения массива имеют значение в параметрах types ([dcl.array]). [Example:

    int f(char*);
    int f(char[]);                  // same as f(char*);
    int f(char[7]);                 // same as f(char*);
    int f(char[9]);                 // same as f(char*);
    
    int g(char(*)[10]);
    int g(char[5][10]);             // same as g(char(*)[10]);
    int g(char[7][10]);             // same as g(char(*)[10]);
    int g(char(*)[20]);             // different from g(char(*)[10]);
    

    end example]

  • Объявления параметров, которые отличаются только тем, что один является типом функции, а другой - указателем на тот же тип функции, эквивалентны. То есть тип функции корректируется, чтобы стать указателем на функцию type ([dcl.fct]). [Example:

    void h(int());
    void h(int (*)());              // redeclaration of h(int())
    void h(int x()) { }             // definition of h(int())
    void h(int (*x)()) { }          // ill-formed: redefinition of h(int())
    

    end example]

  • Объявления параметров, которые отличаются только наличием или отсутствием const и / или volatile эквивалентны. То есть, const и volatile типа-спецификаторы для каждого типа параметра игнорируется при определении того, какие функции объявляются, определяются или вызываются. [Example:

    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)
    

    end example]

    Только const и volatile на самом внешнем уровне спецификации типа параметра игнорируется таким образом спецификаторы типа; const а volatile спецификаторы типа, скрытые в спецификации типа параметра, имеют важное значение и могут использоваться для различения объявлений перегруженных функций.123 В частности, для любого типа T«указатель на T», «указатель на const T» и «указатель на volatile T» считаются отдельными типами параметров, как и «ссылка на T», «ссылка на const T» и «ссылка на volatile T».

  • Два объявления параметров, которые различаются только аргументами по умолчанию, эквивалентны. [ Example: Учтите следующее:

    void f (int i, int j);
    void f (int i, int j = 99);     // OK: redeclaration of f(int, int)
    void f (int i = 88, int j);     // OK: redeclaration of f(int, int)
    void f ();                      // OK: overloaded declaration of f
    
    void prog () {
        f (1, 2);                   // OK: call f(int, int)
        f (1);                      // OK: call f(int, int)
        f ();                       // Error: f(int, int) or f()?
    }

    end example]

end note]

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