0

I am primarily making this post to clarify some confusing/misleading information about function pointers that I stumbled upon on Stackoverflow.

Let's begin with an example:

#include <iostream>

void func ()
{
    std::cout<<"func here"<<'\n';
}

int main()
{
    void (*fp)()=func;
    void (&fref)()=func;

    func();//call through function
    (&func)();//call through function pointer
    (*fp)();//call through function
    fp();//call through function pointer
    fref();//call through function
    (&fref)();//call through function pointer
}

This prints:

func here
func here
func here
func here
func here
func here

As can be seen a function can be used in place of a function pointer most of the time thanks to function to function pointer decay cppreference.

An lvalue of function type T can be implicitly converted to a prvalue pointer to that function. This does not apply to non-static member functions because lvalues that refer to non-static member functions do not exist.

But apart from that it looks a function pointer can also be used in place of a function as I can use it to call a function without explicitly derefencing.

Furthermore this Stackoverflow answer

Note also that you do not need to use the unary * to make the call via the function pointer; both (*p1_foo)(); and (p1_foo)(); have the same result, again because of the function-to-function-pointer conversion.

and this Stackoverflow answer

There's a dual convenience as well: a function pointer in call position is automatically converted to a function value, so you don't have to write * to call through a function pointer.

Make it seem like there exists an implicit function pointer to function conversion.

Lundin
  • 195,001
  • 40
  • 254
  • 396
Aiko
  • 183
  • 9
  • 3
    Please don't cross tag C and C++ just for the sake of it. They are very different languages. Particularly when asking language lawyer questions. – Lundin Aug 24 '22 at 13:33
  • Dup of [Is the asterisk optional when calling a function pointer?](https://stackoverflow.com/questions/23960436/is-the-asterisk-optional-when-calling-a-function-pointer) – Language Lawyer Aug 24 '22 at 13:38
  • @LanguageLawyer thanks for the link, but I already answered my question (QnA style) and what I wanted to stress is that the function to function pointer decay only works one way. – Aiko Aug 24 '22 at 13:41

1 Answers1

5

No

An implicit conversion from function pointer to function doesn't exist.

As of ISO International Standard ISO/IEC 14882:2020(E) – Programming Language C++ there are no mentions of such a conversion.

But apart from that it looks a function pointer can also be used in place of a function as I can use it to call a function without explicitly derefencing.

This is probably why some SO answers (and even some less known C++ books!) come to the incorrect conclusion that a function pointer is essentially the same as a function and use the function to function pointer decay as evidence. However this implicit conversion only works in one way! Meaning that the quoted section of the first SO answer is incorrect.

Why does the function call succeed anyway?

The reason as to why we can call a function using a function pointer without explicit derefernce actually lies in the way the built in function call operator "()" works cppreference:

The expression that names the function can be a) lvalue expression that refers to a function b) pointer to function c) explicit class member access expression that selects a member function d) implicit class member access expression, e.g. member function name used within another member function.

Aha! So the function call operator can directly take a function pointer as expression. There is no implicit conversion. If you read the quote from the second SO answer it explicitly mentions that the function pointer needs to be in call position that is called using the function call operator.

This also means that in all contexts outside of a function call a function pointer does need to be dereferenced where a function is expected such as when initializing a function reference:

void func ()
{
    std::cout<<"func here"<<'\n';
}

int main()
{
    void (*fp)()=func;//OK (implicit function to function pointer decay)

    void (&&fref1)()=&func;//error: invalid initialization of reference of type 'void (&&)()' from expression of type 'void (*)()'

    void (&fref2)()=*fp;//OK

    void (&fref3)()=fp;// error: invalid initialization of reference of type 'void (&)()' from expression of type 'void (*)()'
}

Aiko
  • 183
  • 9
  • Traditionally, functions whenever used in expressions decay into a pointer to that function. Much like arrays decay into a pointer to the first element. That's how C works and that's traditionally how C++ works too. If later C++ standards have changed the wording regarding this, I wouldn't know. – Lundin Aug 24 '22 at 13:36
  • Yes, that's exactly what I wanted to stress, is that the decay works only in one way that is from function **to** function pointer. Not the other way around, as some SO anwsers might suggest. – Aiko Aug 24 '22 at 13:38
  • That decay would happen if you just write `func;` as well. That the result is getting assigned to a function pointer has nothing to do with it. In C the relevant part is found in C17 6.3.2.1: "A _function designator_ is an expression that has function type. Except when it is the operand of the sizeof operator, or the unary & operator, a function designator with type ‘‘function returning type’’ is converted to an expression that has type ‘‘pointer to function returning type’’. – Lundin Aug 24 '22 at 13:40
  • 1
    _That's how C works and that's traditionally how C++ works too. If later C++ standards have changed the wording regarding this, I wouldn't know._ In C++, lvalues of function type are not converted to function pointers in a function call. It has been like this since C++98. – Language Lawyer Aug 24 '22 at 13:40
  • 1
    _That decay would happen if you just write `func;` as well._ Has never been happening in C++ – Language Lawyer Aug 24 '22 at 13:42
  • @Lundin *"That decay would happen if you just write func; as well"*, No in C++ the decay only happens when necessary. How else would you initialize a function reference? In my question I initialized a function reference without explicit dereference. In my answer I then demonstrated, that a function reference can't be initialized with a pointer. If func were always converted to a pointer an implicit function pointer to function would be necessary, which however as discussed doesn't exist. – Aiko Aug 25 '22 at 12:19