Namespaces
Variants

Address of an overloaded function

From cppreference.net
C++ language
General topics
Flow control
Conditional execution statements
Iteration statements (loops)
Jump statements
Functions
Function declaration
Lambda function expression
inline specifier
Dynamic exception specifications ( until C++17* )
noexcept specifier (C++11)
Exceptions
Namespaces
Types
Specifiers
constexpr (C++11)
consteval (C++20)
constinit (C++20)
Storage duration specifiers
Initialization
Expressions
Alternative representations
Literals
Boolean - Integer - Floating-point
Character - String - nullptr (C++11)
User-defined (C++11)
Utilities
Attributes (C++11)
Types
typedef declaration
Type alias declaration (C++11)
Casts
Memory allocation
Classes
Class-specific function properties
Special member functions
Templates
Miscellaneous

Besides function-call expressions , where overload resolution takes place, the name of an overloaded function may appear in the following 7 contexts:

# Context Target
1 initializer in a declaration of an object or reference the object or reference being initialized
2 on the right-hand-side of an built-in assignment expression the left-hand side of the built-in assignment
3 as a function call argument the function parameter
4 as a user-defined operator argument the operator parameter
5 the return statement the return value of a function or conversion
6 explicit cast or static_cast argument the corresponding cast
7 constant template argument the corresponding template parameter

In each context, the name of an overloaded function may be preceded by address-of operator & and may be enclosed in a redundant set of parentheses.

If the target type contains a placeholder type , placeholder type deduction is performed, and the following description uses the deduced type as target type.

(since C++26)

Contents

Selecting functions

When the address of an overloaded function is taken, a set S of functions is selected from the overload set referred to by the name of the overload function:

  • If there is no target, all non-template functions named are selected.
  • Otherwise, a non-template function with type F is selected for the function type FT of the target type if F (after possibly applying the function pointer conversion ) (since C++17) is identical to FT . [1]
  • The specialization (if any) generated by template argument deduction for each function template named is also added to S .

If the target is of function pointer type or reference to function type, S can only include non-member functions , explicit object member functions (since C++23) and static member functions. If the target is of pointer-to-member-function type, S can only include implicit object member functions.

  1. In other words, the class of which the function is a member is ignored if the target type is a pointer-to-member-function type.

Eliminating functions

After forming the set S , functions are elimiated in the following order:

  • All functions with associated constraints that are not satisfied are eliminated from the S .
(since C++20)
  • If more than one function in S remains, all function template specializations in S are eliminated if S also contains a non-template function.
(since C++20)
  • Any given function template specialization spec is eliminated if S contains a second function template specialization whose function template is more specialized than the function template of spec .

After such eliminations (if any), exactly one selected function should remain in S . Otherwise, the program is ill-formed.

Example

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);
}

Defect reports

The following behavior-changing defect reports were applied retroactively to previously published C++ standards.

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

References

  • C++23 standard (ISO/IEC 14882:2024):
  • 12.3 Address of overloaded function [over.over]
  • C++20 standard (ISO/IEC 14882:2020):
  • 12.5 Address of overloaded function [over.over]
  • C++17 standard (ISO/IEC 14882:2017):
  • 16.4 Address of overloaded function [over.over]
  • C++14 standard (ISO/IEC 14882:2014):
  • 13.4 Address of overloaded function [over.over]
  • C++11 standard (ISO/IEC 14882:2011):
  • 13.4 Address of overloaded function [over.over]
  • C++98 standard (ISO/IEC 14882:1998):
  • 13.4 Address of overloaded function [over.over]