Function pointer vs Function reference
Asked Answered
N

4

33

In the code below, function-pointer and what i considered as "function-reference" seems to have identical semantics:

#include <iostream>
using std::cout;

void func(int a) {
    cout << "Hello" << a << '\n';
}
void func2(int a) {
    cout << "Hi" << a << '\n';
}

int main() {
    void (& f_ref)(int) = func;
    void (* f_ptr)(int) = func;

    // what i expected to be, and is, correct:
    f_ref(1);
    (*f_ptr)(2);

    // what i expected to be, and is not, wrong:
    (*f_ref)(4); // i even added more stars here like (****f_ref)(4)
    f_ptr(3);    // everything just works!

    // all 4 statements above works just fine

    // the only difference i found, as one would expect:
//  f_ref = func2; // ERROR: read-only reference
    f_ptr = func2; // works fine!
    f_ptr(5);

    return 0;
}

I used gcc version 4.7.2 in Fedora/Linux

UPDATE

My questions are:

  1. Why function pointer does not require dereferencing?
  2. Why dereferencing a function reference doesn't result in an error?
  3. Is(Are) there any situation(s) where I must use one over the other?
  4. Why f_ptr = &func; works? Since func should be decayed into a pointer?
    While f_ptr = &&func; doesn't work (implicit conversion from void *)
Nicolis answered 5/10, 2013 at 17:18 Comment(0)
C
20

Functions and function references (i.e. id-expressions of those types) decay into function pointers almost immediately, so the expressions func and f_ref actually become function pointers in your case. You can also call (***func)(5) and (******f_ref)(6) if you like.

It may be preferable to use function references in cases where you want the &-operator to work as though it had been applied to the function itself, e.g. &func is the same as &f_ref, but &f_ptr is something else.

Counterchange answered 5/10, 2013 at 17:22 Comment(4)
is that an implementation bug? 'coz that goes against our intuitive concepts of "typing", right? I have also seen something like void (*&f)(void) as a parameter to function - * and & used together.. how come?Nicolis
It's not a bug, just the way the language is defined. In expressions there are basically no functions, there are only ever function pointers; decay takes care of making the "obvious" syntax work (i.e. you can type f(1) rather than the more cumbersome (&f)(1)).Counterchange
@John: Compare to the way arrays are handled; they can't be passed by value, so in a function prototype, int x[] (and for that matter (int x[10]) is equivalent to int *x; since receiving a C array by value isn't legal, they let array declaration syntax be used as syntactic sugar for receiving a pointer.Insolation
@KerrekSB Does &f_ptr return the address of the pointer to the function?Security
M
16

"Why function pointer does not require dereferencing?"

Because the function identifier itself is actually a pointer to the function already:

4.3 Function-to-pointer conversion
§1 An lvalue of function type T can be converted to an rvalue of type “pointer to T.” The result is a pointer to the function.

"Why dereferencing a function reference doesn't result in an error?"

Basically you can look at defining a reference as defining an alias (alternative name). Even in the standard in 8.3.2 References in part addressing creating a reference to an object, you will find:
"a reference can be thought of as a name of an object."

So when you define a reference:

void (& f_ref)(int) = func;

it gives you the ability to use f_ref almost everywhere where it would be possible to use func, which is the reason why:

f_ref(1);
(*f_ref)(4);

works exactly the same way as using the func directly:

func(1);
(*func)(4);
Metz answered 5/10, 2013 at 17:37 Comment(0)
B
4

See here.

The address-of operator acts like you would expect, as it points to a function but cannot be assigned. Functions are converted to function pointers when used as rvalues, which means you can dereference a function pointer any number of times and get the same function pointer back.

Backwater answered 5/10, 2013 at 17:34 Comment(0)
D
2

As there are good answers from other people here, there is no answer explaining why f_ptr = &&func; does not work. When you apply the addressof operator & to a variable/function, you get its address. The adress itself is an r-value/a temporary variable. You cannot take the address of a temporary.

But it seems that there is a type error. The message implicit conversion from void* is very compiler specific for this code. I guess you are using GCC/Clang. GCC/Clang offers the ability to take the address of labels like &&label. The resulting value is of type void*. Other compilers will output something like cannot take address of temporary or invalid syntax. When using these compilers this kind of error could have been hidden without any warning in special circumstances:

int main() {
    int foo = 42;
    foo:;
    void* a = &foo; // take the address of a variable/function
    void* b = &&foo; // take the address of a label

    std::cout << *(int*)a << '\n';
    goto *b;
};

But who would name everything the same?

Duchamp answered 12/5, 2019 at 11:22 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.