3

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)?

songyuanyao
  • 169,198
  • 16
  • 310
  • 405
Afshin
  • 8,839
  • 1
  • 18
  • 53
  • 4
    https://stackoverflow.com/questions/4328215/why-does-a-function-name-evaluate-to-true-in-c-and-how-to-get-warned-on-it - it's using it as a bool. – Caramiriel Nov 03 '18 at 07:43
  • Note that “foo” is *not* “a qualified name of a non-static member” – `foo` isn’t even a member of anything – so the text you quoted does not apply. – molbdnilo Nov 03 '18 at 07:48
  • 1
    Adding another ref: https://en.cppreference.com/w/cpp/io/basic_ostream/operator_ltlt - see notes section – Caramiriel Nov 03 '18 at 07:51
  • @Caramiriel in that question there is no conversion to `bool`. Address of a function is always non-zero so is evaluated (not converted) to true. In this question there is a conversion to `bool` because no overloads of `operator<<` best match to function pointer arguments other than `bool`. – E. Vakili Nov 03 '18 at 07:53

3 Answers3

6

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.

songyuanyao
  • 169,198
  • 16
  • 310
  • 405
  • why function pointers can not implicitly converted to `const void*`? – 463035818_is_not_an_ai Nov 03 '18 at 08:12
  • yea it is strange for me too. why function pointer is not implicitly cast to `const void*`? Is there any standard restriction for this? because converting to `const void*` is much more logical than `bool`.... – Afshin Nov 03 '18 at 08:13
  • 1
    @user463035818 Afshin There's just no such implicit convesion; only pointer to object type could conver to `void*` implicitly. See [Pointer conversions](https://en.cppreference.com/w/cpp/language/implicit_conversion#Pointer_conversions). – songyuanyao Nov 03 '18 at 08:16
  • @songyuanyao hmm: *A prvalue pointer to any (optionally cv-qualified) object type T can be converted to a prvalue pointer to (identically cv-qualified) void.* shouldn't this apply to function pointers too? – Afshin Nov 03 '18 at 08:18
  • @Afshin No, *object type* is not *function type*. – songyuanyao Nov 03 '18 at 08:20
  • Because implicit conversion for function pointer to `void *` is possible in `C`, I was expected to be possible in `C++` too. My mistake, but I didn't think this has changed. – Afshin Nov 03 '18 at 08:46
  • @Afshin There're many subtle differences between C++ and C; it's better to just think they're different language. – songyuanyao Nov 03 '18 at 08:51
  • @Afshin C has no implicit conversion from pointers to functions to void*. If you're using gcc, never forget `-pedantic-errors` – Cubbi Nov 14 '18 at 14:34
  • @Cubbi but standard states that: *A pointer to void can be implicitly converted to and from any pointer to object type* – Afshin Nov 14 '18 at 15:04
  • @Afshin sure, but that is not relevant. This discussion is about function pointers. – Cubbi Nov 15 '18 at 02:32
  • @Cubbi oh,my mistake. thanks for info. – Afshin Nov 15 '18 at 05:55
  • "*note there's no overload taking function pointer*" - actually, there is (3 overloads, in fact). It is just that such function pointers must have a specific signature in order to be passed to `operator<<`, and the functions in question simply do not match those signatures. – Remy Lebeau Apr 18 '23 at 01:03
1

There is no overload for operator<< that matches the function pointer. So best match is basic_ostream& operator<<(bool value).

There is another overload of operator<< as basic_ostream& operator<<(const void * value). But function pointers could not implicitly cast to const void*.

If you would like to print the address of a function you could cast it to void * by using reinterpret_cast or C style casts.

E. Vakili
  • 1,036
  • 1
  • 10
  • 25
1

What you see is that the

std::ostream& operator<<( bool );

From cppreference:

There are no overload for pointers to non-static member, pointers to volatile, or function pointers (other than the ones with signatures accepted by the (10-12) overloads). Attempting to output such objects invokes implicit conversion to bool, and, for any non-null pointer value, the value 1 is printed (unless boolalpha was set, in which case true is printed).

To see the pointer value you can cast to void*:

std::cout << (void*)foo;
463035818_is_not_an_ai
  • 109,796
  • 11
  • 89
  • 185