12 Overloading [over]

12.2 Overloadable declarations [over.load]

Not all function declarations can be overloaded.
Those that cannot be overloaded are specified here.
A program is ill-formed if it contains two such non-overloadable declarations in the same scope.
Note
:
This restriction applies to explicit declarations in a scope, and between such declarations and declarations made through a using-declaration.
It does not apply to sets of functions fabricated as a result of name lookup (e.g., because of using-directives) or overload resolution (e.g., for operator functions).
— end note
 ]
Certain function declarations cannot be overloaded:
Note
:
As specified in [dcl.fct], function declarations that have equivalent parameter declarations and requires-clauses, if any ([temp.constr.decl]), declare the same function and therefore cannot be overloaded:
  • Parameter declarations that differ only in the use of equivalent typedef “types” are equivalent.
    A typedef is not a separate type, but only a synonym for another type.
    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
     ]
    Enumerations, on the other hand, are distinct types and can be used to distinguish overloaded function declarations.
    Example
    :
    enum E { a };
    
    void f(int i) { /* ... */ }
    void f(E i)   { /* ... */ }
    
    — end example
     ]
  • Parameter declarations that differ only in a pointer * versus an array [] are equivalent.
    That is, the array declaration is adjusted to become a pointer declaration ([dcl.fct]).
    Only the second and subsequent array dimensions are significant in parameter 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
     ]
  • Parameter declarations that differ only in that one is a function type and the other is a pointer to the same function type are equivalent.
    That is, the function type is adjusted to become a pointer to function 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)()) { }          // error: redefinition of h(int())
    
    — end example
     ]
  • Parameter declarations that differ only in the presence or absence of const and/or volatile are equivalent.
    That is, the const and volatile type-specifiers for each parameter type are ignored when determining which function is being declared, defined, or called.
    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
     ]
    Only the const and volatile type-specifiers at the outermost level of the parameter type specification are ignored in this fashion; const and volatile type-specifiers buried within a parameter type specification are significant and can be used to distinguish overloaded function declarations.116
    In particular, for any type T, “pointer to T”, “pointer to const T”, and “pointer to volatile T” are considered distinct parameter types, as are “reference to T”, “reference to const T”, and “reference to volatile T.
  • Two parameter declarations that differ only in their default arguments are equivalent.
    Example
    :
    Consider the following:
    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
 ]
When a parameter type includes a function type, such as in the case of a parameter type that is a pointer to function, the const and volatile type-specifiers at the outermost level of the parameter type specifications for the inner function type are also ignored.