Function pointer vs Function reference

10,998

Solution 1

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.

Solution 2

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

Solution 3

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.

Solution 4

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?

Share:
10,998
John
Author by

John

Working as a Machine Learning Engineer. Silent follower of the Rust community. Tried Vim once, and have been in love ever since.

Updated on June 11, 2022

Comments

  • John
    John almost 2 years

    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 *)
  • John
    John over 10 years
    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?
  • Kerrek SB
    Kerrek SB over 10 years
    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)).
  • ShadowRanger
    ShadowRanger over 8 years
    @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.