c++function-pointersstd-function

What different between "typeSpecifier functionPointer = & definedFunction" and "typeSpecifier functionPointer = definedFunction"?


Please considering the following example first (this is a part of the code from Cplusplus.com):

#include <iostream>     // std::cout
#include <functional>   // std::function, std::negate

int half(int x) {return x/2;}

int main () {
  std::function<int(int)> fn1 = half;                    // function
  std::function<int(int)> fn2 = &half;                   // function pointer
  std::cout << "fn1(60): " << fn1(60) << '\n';
  std::cout << "fn2(60): " << fn2(60) << '\n';
  return 0;
}

What different between fn1 and fn2 in the examle?
Does that mean that fn1 will COPY the function "half", whereas fn2 is just point to that function. The comments by Cplusplus.com imply they're different ; but I've heard from some video said that they're the same and the operator "&" is just optional.
So what is the truth? please help.


Solution

  • If the typeSpecifier is an object, then there is no practical difference in most cases. In your code, using half and &half does exactly the same. It's still worth noting that there are two different effects involved:

    Function-to-pointer conversion

    auto f = function;
    

    This forces an implicit conversion of function to an object, and is called function-to-pointer conversion:

    An lvalue of function type T can be converted to a prvalue of type “pointer to T”. The result is a pointer to the function.

    - [conv.func] p1

    Note that your code does not perform function-to-pointer conversion explicitly, because you implicitly call the following constructor:

    // You end up calling this with F = int(&)(int)
    // i.e. a reference to a function taking int and returning int.
    // (See https://cdecl.plus/?q=int%28%26%29%28int%29 for learning type syntax)
    template<class F>
    function(F&& f);
    

    This constructor uses std::decay_t and performs function-to-pointer conversion internally.

    Taking the address of a function with &

    auto f = &function;
    

    This takes the address of the function explicitly:

    The operand of the unary & operator shall be an lvalue of some type T. The result is a prvalue.

    • [...]
    • Otherwise, the result has type "pointer to T" and points to the designated object or function.

    - [expr.unary.op] p3

    In your example, you still call the aforementioned constructor. However, this time you are passing in a "function pointer" int(*)(int), not "function reference" int(&)(int). The end result is the same.