Function pointer vs Function reference
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.
When to use function reference instead of function pointer in C++?
when you define a reference:
void (&fr)() = foo;
fr();
it gives you the ability to use fr
almost everywhere where it would be possible to use foo
, which is the reason why:
fr();
(*fr)();
works exactly the same way as using the foo
directly:
foo();
(*foo)();
One more Difference is dereferencing a function reference doesn't result in an error where function pointer does not require dereferencing.
C++ What's the difference between function_pointer and &function_pointer?
Function designators are implicitly converted to pointers to the function types.
From the C++ Standard (4.3 Function-to-pointer conversion)
1 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
So these declarations
int (*f)() = &No; //method 1
int (*f2)() = No; //method 2
are equivalent. In the first declaration the function designator is converted to pointer explicitly while in the second declaration the function designator is converted to pointer implicitly.
In the call of the function in this statement
std::cout << (*f)() << std::endl;
using the expression *f
is redundant because again the function designator *f
is converted to pointer. You could just write
std::cout << f() << std::endl;
If you want you can even write
std::cout << (*******f)() << std::endl;
The result will be the same.
Here is a demonstrative program.
#include <iostream>
int No() { return 5; }
int main()
{
int (*f)() = &No; //method 1
int (*f2)() = No; //method 2
std::cout << f() << std::endl; //prints out 5
std::cout << ( *******f2 )() << std::endl; //prints out 5
return 0;
}
That is dereferencing the pointer *f2
yields lvalue of the function type that in turn again is converted to function pointer.
Pointers vs. References in C++ function arguments
The first approach is called "passing by pointer"; the second approach is called "passing by reference". In the first case, dereference is explicit; in the second case, dereference is implicit.
The biggest difference between the two approaches is that when you pass by pointer, you can pass "nothing" (i.e. a null pointer). When you pass by reference, it is not possible to legally pass a reference to nothing: it should be a reference to some variable, an array element, a field of a class or a structure, etc.
When you need to return a value and modify a variable, passing by reference is more appropriate, because the variable that you need to modify always exists. Passing by pointer becomes more appropriate in situations when you traverse a dynamic data structure connected by pointers, when parts of that data structure may or may not exist.
Why can I assign to a function pointer both a reference to a function a the function itself?
This is pretty much an exact duplicate of this question
The answer is that functions can be implicitly converted to function pointers (similar to array to pointer decay) per the spec.
Function Pointers by Reference
Your premise is false. You don't need an &
in front of a function to pass it to delIf
. The name of a function decays into a pointer to the function almost everywhere it is used in an expression. (Including when you call the function!) In fact, the only place it doesn't is when it is used as an argument to &
- so
func
&func
have exactly the same type and value.
Having said that, yes you can pass a reference. First rule of pointers to functions - write a typedef
typedef bool pred_t(T);
void delIf( pred_t& pred );
But! I strongly encourage you to write delIf
as a function template, and allow anything which can be called with a T
, and has a function result which can be implicitly converted to bool
.
template <typename Pred>
void delIf(Pred pred) {
...
}
That will allow use with capturing lambdas, and functors in general.
Also, what is this CPP file of which you speak? Templates have to be implemented in the header file. See the answers to this question.
(Note: "Pred" is short for "predicate" which is what the standard calls this sort of function.)
Should I use std::function or a function pointer in C++?
In short, use std::function
unless you have a reason not to.
Function pointers have the disadvantage of not being able to capture some context. You won't be able to for example pass a lambda function as a callback which captures some context variables (but it will work if it doesn't capture any). Calling a member variable of an object (i.e. non-static) is thus also not possible, since the object (this
-pointer) needs to be captured.(1)
std::function
(since C++11) is primarily to store a function (passing it around doesn't require it to be stored). Hence if you want to store the callback for example in a member variable, it's probably your best choice. But also if you don't store it, it's a good "first choice" although it has the disadvantage of introducing some (very small) overhead when being called (so in a very performance-critical situation it might be a problem but in most it should not). It is very "universal": if you care a lot about consistent and readable code as well as don't want to think about every choice you make (i.e. want to keep it simple), use std::function
for every function you pass around.
Think about a third option: If you're about to implement a small function which then reports something via the provided callback function, consider a template parameter, which can then be any callable object, i.e. a function pointer, a functor, a lambda, a std::function
, ... Drawback here is that your (outer) function becomes a template and hence needs to be implemented in the header. On the other hand you get the advantage that the call to the callback can be inlined, as the client code of your (outer) function "sees" the call to the callback will the exact type information being available.
Example for the version with the template parameter (write &
instead of &&
for pre-C++11):
template <typename CallbackFunction>
void myFunction(..., CallbackFunction && callback) {
...
callback(...);
...
}
As you can see in the following table, all of them have their advantages and disadvantages:
function ptr | std::function | template param | |
---|---|---|---|
can capture context variables | no1 | yes | yes |
no call overhead (see comments) | yes | no | yes |
can be inlined (see comments) | no | no | yes |
can be stored in a class member | yes | yes | no2 |
can be implemented outside of header | yes | yes | no |
supported without C++11 standard | yes | no3 | yes |
nicely readable (my opinion) | no | yes | (yes) |
Understanding function pointers and reference
The types instantiated via alias templates type0
through type3
all exist. You can't have objects of a function type, though, i.e., there are no instances of the types instantiated via the alias template type0
.
There is no "reference to member"-type, i.e., I don't think type4
works
The types are reasonably easy to understand:
R(Args...)
is a function value type (returnR
and takingArgs...
as arguments). Essentially, that's the type a function has. C++ doesn't allow values of this type.R(*)(Args...)
is a function pointer type. The parenthesis around the*
(and if there is a name, the name as in(*name)
) are needed to disambiguate whether the*
binds to the return typeR
(the default) or the function type (when there are parenthesis). When you want to pass a function somewhere, you don't use a function value but a function pointer. You can call a function through a function pointer. You can think of a function pointer to be the address where the function implementation lives although there is no guarantee that this is also how it is implemented.R(&)(Args...)
is a function reference type. The relation between function pointers and function reference is the same as that between pointer and reference: you'll get a function reference if you dereference a function pointer.R(C::*)(Args...)
is a member function pointer type. That is essentially a handle for a member function. These are more like indices into lists of member functions but identify a member function. With an objecto
and a member function pointermem
you can call the member function using something like(o.*mem)(args...)
. If the member function used to initialize the pointer to member isvirtual
dynamic dispatch will happen (I don't think there is a way to prevent dynamic dispatch when calling though a member function pointer).
In addition to those function declarations listed the member function pointer type can have const
/volatile
and/or ref-qualification and there are variable argument versions of the function type. That is, there are also
pointer to
const
members:template <class R, class C, class... Args>
using mem_const = R(C::*)(Args...) const`pointer to
volatile
members:template <class R, class C, class... Args>
using mem_volatile = R(C::*)(Args...) volatilepointer to
const volatile
members:template <class R, class C, class... Args>
using mem_const_volatile = R(C::*)(Args...) const volatilepointer to lvalue qualified members:
template <class R, class C, class... Args>
using mem_lvalue = R(C::*)(Args...) &;pointer to rvalue qualified members:
template <class R, class C, class... Args>
using mem_rvalue = R(C::*)(Args...) &&;all combinations of
const
/volatile
and lvalue/rvalue qualification.variable argument list versions of function types (the
......
can alternatively also be written as a... ...
or..., ...
):template <class R, class... Args>
using varargs = R(Args......);All function pointer, reference, and member function pointer types with a trailing variable argument list.
I think this is [currently] a reasonably exhaustive list of functions and member-functions, their qualified version, and their pointer/reference versions. With C++17 also adding exception specifications to the mix, there will also be a noexcept(true)
version (in addition to the default noexcept(false)
one.
Related Topics
Accessing Environment Variables in C++
Why Don't the C or C++ Standards Explicitly Define Char as Signed or Unsigned
What Is the Status of N2965 - Std::Bases and Std::Direct_Bases
Why Does Gcc Generate 15-20% Faster Code If I Optimize for Size Instead of Speed
Run an Application in Gdb Until an Exception Occurs
How to Sort a Std::Map First by Value, Then by Key
Avoiding Copy of Objects with the "Return" Statement
Pseudo-Destructor Call Does Not Destroy an Object
Emulating Shifts on 32 Bytes with Avx
Why Does This Delay-Loop Start to Run Faster After Several Iterations with No Sleep
How to Use String.Substr() Function
Measuring Memory Bandwidth from the Dot Product of Two Arrays
*.H or *.Hpp for Your Class Definitions
Very Poor Boost::Lexical_Cast Performance
C++ Std::Map Holding Any Type of Value
How Is C++ Std::Vector Implemented
How to Generate All Permutations of an Array in Sorted Order