Search code examples
c++function-pointersimplicit-conversion

Why pointer to function is equal to 1?


Check following code:

#include <iostream>
using namespace std;

int& foo() {
    static int i = 0;
    return i;
}

int main() {
    cout << &foo() << endl;
    cout << &foo << endl;

    return 0;
}

As you see, the first cout prints address of return value of foo() which will be static variable i inside foo(). For 2nd cout I was expecting that &foo returns address of foo() function, as stated here:

2) If the operand is a qualified name of a non-static member, e.g. &C::member, the result is a prvalue pointer to member function or pointer to data member of type T in class C. Note that neither &member nor C::member nor even &(C::member) may be used to initialize a pointer to member.

But to my surprise, this is my output:

0x5650dc8dc174
1

First one is ok, but 2nd one is 1? How this happened? To make sure that I have not messed up anything, I wrote this code in C:

#include <stdio.h>

int foo() {
}

int main(void) {
    printf("%p", &foo);
    return 0;
}

with following output:

0x55732bd426f0

which works as expected. Have I missed up something in C++ code? or maybe this is because of inlining foo function (even though it should not be like this)?


Solution

  • std::basic_ostream::operator<< has two overloads taking bool and const void*. (There're other overloads taking function pointer with different signature which doesn't match with foo.)

    basic_ostream& operator<<( bool value );        (6)   
    basic_ostream& operator<<( const void* value ); (7)
    

    For both int* and function pointer passed to std::basic_ostream::operator<<, implicit conversions are required here.

    When passing int*, the (7) overload is selected because the implicit conversion converting from int* to const void* is perferred than the one converting to bool in overload resolution,

    If two conversion sequences are indistinguishable because they have the same rank, the following additional rules apply:

    1. Conversion that involves pointer to bool, pointer-to-member to bool, or std::nullptr_t to bool conversion is worse than the one that doesn't

    and

    A prvalue pointer to any (optionally cv-qualified) object type T can be converted to a prvalue pointer to (identically cv-qualified) void. The resulting pointer represents the same location in memory as the original pointer value.

    When passing function pointer, the (6) overload is selected; function pointer can be converted to bool implicitly, but not to const void*.

    A prvalue of integral, floating-point, unscoped enumeration, pointer, and pointer-to-member types can be converted to a prvalue of type bool.

    The value zero (for integral, floating-point, and unscoped enumeration) and the null pointer and the null pointer-to-member values become false. All other values become true.