In lesson 6.7 -- Introduction to pointers, you learned that a pointer is a variable that holds the address of another variable. Function pointers are similar, except that instead of pointing to variables, they point to functions!
Consider the following function:
1 2 3 4 |
int foo() { return 5; } |
Identifier foo is the function’s name. But what type is the function? Functions have their own l-value function type -- in this case, a function type that returns an integer and takes no parameters. Much like variables, functions live at an assigned address in memory.
When a function is called (via the () operator), execution jumps to the address of the function being called:
1 2 3 4 5 6 7 8 9 10 11 |
int foo() // code for foo starts at memory address 0x002717f0 { return 5; } int main() { foo(); // jump to address 0x002717f0 return 0; } |
At some point in your programming career (if you haven’t already), you’ll probably make a simple mistake:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
#include <iostream> int foo() // code starts at memory address 0x002717f0 { return 5; } int main() { std::cout << foo << '\n'; // we meant to call foo(), but instead we're printing foo itself! return 0; } |
Instead of calling function foo() and printing the return value, we’ve unintentionally sent function foo directly to std::cout. What happens in this case?
On the author’s machine, this printed:
0x002717f0
…but it may print some other value (e.g. 1) on your machine, depending on how your compiler decides to convert the function pointer to another type for printing. If your machine doesn’t print the function’s address, you may be able to force it to do so by converting the function to a void pointer and printing that:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
#include <iostream> int foo() // code starts at memory address 0x002717f0 { return 5; } int main() { std::cout << reinterpret_cast<void*>(foo) << '\n'; // Tell C++ to interpret function foo as a void pointer return 0; } |
Just like it is possible to declare a non-constant pointer to a normal variable, it’s also possible to declare a non-constant pointer to a function. In the rest of this lesson, we’ll examine these function pointers and their uses. Function pointers are a fairly advanced topic, and the rest of this lesson can be safely skipped or skimmed by those only looking for C++ basics.
Pointers to functions
The syntax for creating a non-const function pointer is one of the ugliest things you will ever see in C++:
1 2 |
// fcnPtr is a pointer to a function that takes no arguments and returns an integer int (*fcnPtr)(); |
In the above snippet, fcnPtr is a pointer to a function that has no parameters and returns an integer. fcnPtr can point to any function that matches this type.
The parenthesis around *fcnPtr are necessary for precedence reasons, as int *fcnPtr()
would be interpreted as a forward declaration for a function named fcnPtr that takes no parameters and returns a pointer to an integer.
To make a const function pointer, the const goes after the asterisk:
1 |
int (*const fcnPtr)(); |
If you put the const before the int, then that would indicate the function being pointed to would return a const int.
Assigning a function to a function pointer
Function pointers can be initialized with a function (and non-const function pointers can be assigned a function). In the above example, we have used foo directly, and it has been converted to a function pointer. Like with pointers to variables, we can also use &foo to get a function pointer to foo. For consistency with variable pointers and member function pointers, which we’ll cover in a future lesson, we’ll be using the &foo syntax rather than just foo.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
int foo() { return 5; } int goo() { return 6; } int main() { int (*fcnPtr)(){ &foo }; // fcnPtr points to function foo fcnPtr = &goo; // fcnPtr now points to function goo return 0; } |
One common mistake is to do this:
1 |
fcnPtr = goo(); |
This would actually assign the return value from a call to function goo() to fcnPtr, which isn’t what we want. We want fcnPtr to be assigned the address of function goo, not the return value from function goo(). So no parenthesis are needed.
Note that the type (parameters and return type) of the function pointer must match the type of the function. Here are some examples of this:
1 2 3 4 5 6 7 8 9 10 11 |
// function prototypes int foo(); double goo(); int hoo(int x); // function pointer assignments int (*fcnPtr1)(){ &foo }; // okay int (*fcnPtr2)(){ &goo }; // wrong -- return types don't match! double (*fcnPtr4)(){ &goo }; // okay fcnPtr1 = &hoo; // wrong -- fcnPtr1 has no parameters, but hoo() does int (*fcnPtr3)(int){ &hoo }; // okay |
Unlike fundamental types, C++ will implicitly convert a function into a function pointer if needed (so you don’t need to use the address-of operator (&) to get the function’s address). However, it will not implicitly convert function pointers to void pointers, or vice-versa.
Calling a function using a function pointer
The other primary thing you can do with a function pointer is use it to actually call the function. There are two ways to do this. The first is via explicit dereference:
1 2 3 4 5 6 7 8 9 10 11 12 |
int foo(int x) { return x; } int main() { int (*fcnPtr)(int){ &foo }; // Initialize fcnPtr with function foo (*fcnPtr)(5); // call function foo(5) through fcnPtr. return 0; } |
The second way is via implicit dereference:
1 2 3 4 5 6 7 8 9 10 11 12 |
int foo(int x) { return x; } int main() { int (*fcnPtr)(int){ &foo }; // Initialize fcnPtr with function foo fcnPtr(5); // call function foo(5) through fcnPtr. return 0; } |
As you can see, the implicit dereference method looks just like a normal function call -- which is what you’d expect, since normal function names are pointers to functions anyway! However, some older compilers do not support the implicit dereference method, but all modern compilers should.
One interesting note: Default parameters won’t work for functions called through function pointers. Default parameters are resolved at compile-time (that is, if you don’t supply an argument for a defaulted parameter, the compiler substitutes one in for you when the code is compiled). However, function pointers are resolved at run-time. Consequently, default parameters can not be resolved when making a function call with a function pointer. You’ll explicitly have to pass in values for any defaulted parameters in this case.
Passing functions as arguments to other functions
One of the most useful things to do with function pointers is pass a function as an argument to another function. Functions used as arguments to another function are sometimes called callback functions.
Consider a case where you are writing a function to perform a task (such as sorting an array), but you want the user to be able to define how a particular part of that task will be performed (such as whether the array is sorted in ascending or descending order). Let’s take a closer look at this problem as applied specifically to sorting, as an example that can be generalized to other similar problems.
Many comparison-based sorting algorithms work on a similar concept: the sorting algorithm iterates through a list of numbers, does comparisons on pairs of numbers, and reorders the numbers based on the results of those comparisons. Consequently, by varying the comparison, we can change the way the algorithm sorts without affecting the rest of the sorting code.
Here is our selection sort routine from a previous lesson:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
#include <utility> // for std::swap void SelectionSort(int *array, int size) { // Step through each element of the array for (int startIndex{ 0 }; startIndex < (size - 1); ++startIndex) { // smallestIndex is the index of the smallest element we've encountered so far. int smallestIndex{ startIndex }; // Look for smallest element remaining in the array (starting at startIndex+1) for (int currentIndex{ startIndex + 1 }; currentIndex < size; ++currentIndex) { // If the current element is smaller than our previously found smallest if (array[smallestIndex] > array[currentIndex]) // COMPARISON DONE HERE { // This is the new smallest number for this iteration smallestIndex = currentIndex; } } // Swap our start element with our smallest element std::swap(array[startIndex], array[smallestIndex]); } } |
Let’s replace that comparison with a function to do the comparison. Because our comparison function is going to compare two integers and return a boolean value to indicate whether the elements should be swapped, it will look something like this:
1 2 3 4 |
bool ascending(int x, int y) { return x > y; // swap if the first element is greater than the second } |
And here’s our selection sort routine using the ascending() function to do the comparison:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
#include <utility> // for std::swap void SelectionSort(int *array, int size) { // Step through each element of the array for (int startIndex{ 0 }; startIndex < (size - 1); ++startIndex) { // smallestIndex is the index of the smallest element we've encountered so far. int smallestIndex{ startIndex }; // Look for smallest element remaining in the array (starting at startIndex+1) for (int currentIndex{ startIndex + 1 }; currentIndex < size; ++currentIndex) { // If the current element is smaller than our previously found smallest if (ascending(array[smallestIndex], array[currentIndex])) // COMPARISON DONE HERE { // This is the new smallest number for this iteration smallestIndex = currentIndex; } } // Swap our start element with our smallest element std::swap(array[startIndex], array[smallestIndex]); } } |
Now, in order to let the caller decide how the sorting will be done, instead of using our own hard-coded comparison function, we’ll allow the caller to provide their own sorting function! This is done via a function pointer.
Because the caller’s comparison function is going to compare two integers and return a boolean value, a pointer to such a function would look something like this:
1 |
bool (*comparisonFcn)(int, int); |
So, we’ll allow the caller to pass our sort routine a pointer to their desired comparison function as the third parameter, and then we’ll use the caller’s function to do the comparison.
Here’s a full example of a selection sort that uses a function pointer parameter to do a user-defined comparison, along with an example of how to call it:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 |
#include <utility> // for std::swap #include <iostream> // Note our user-defined comparison is the third parameter void selectionSort(int *array, int size, bool (*comparisonFcn)(int, int)) { // Step through each element of the array for (int startIndex{ 0 }; startIndex < (size - 1); ++startIndex) { // bestIndex is the index of the smallest/largest element we've encountered so far. int bestIndex{ startIndex }; // Look for smallest/largest element remaining in the array (starting at startIndex+1) for (int currentIndex{ startIndex + 1 }; currentIndex < size; ++currentIndex) { // If the current element is smaller/larger than our previously found smallest if (comparisonFcn(array[bestIndex], array[currentIndex])) // COMPARISON DONE HERE { // This is the new smallest/largest number for this iteration bestIndex = currentIndex; } } // Swap our start element with our smallest/largest element std::swap(array[startIndex], array[bestIndex]); } } // Here is a comparison function that sorts in ascending order // (Note: it's exactly the same as the previous ascending() function) bool ascending(int x, int y) { return x > y; // swap if the first element is greater than the second } // Here is a comparison function that sorts in descending order bool descending(int x, int y) { return x < y; // swap if the second element is greater than the first } // This function prints out the values in the array void printArray(int *array, int size) { for (int index{ 0 }; index < size; ++index) { std::cout << array[index] << ' '; } std::cout << '\n'; } int main() { int array[9]{ 3, 7, 9, 5, 6, 1, 8, 2, 4 }; // Sort the array in descending order using the descending() function selectionSort(array, 9, descending); printArray(array, 9); // Sort the array in ascending order using the ascending() function selectionSort(array, 9, ascending); printArray(array, 9); return 0; } |
This program produces the result:
9 8 7 6 5 4 3 2 1 1 2 3 4 5 6 7 8 9
Is that cool or what? We’ve given the caller the ability to control how our selection sort does its job.
The caller can even define their own “strange” comparison functions:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
bool evensFirst(int x, int y) { // if x is even and y is odd, x goes first (no swap needed) if ((x % 2 == 0) && !(y % 2 == 0)) return false; // if x is odd and y is even, y goes first (swap needed) if (!(x % 2 == 0) && (y % 2 == 0)) return true; // otherwise sort in ascending order return ascending(x, y); } int main() { int array[9]{ 3, 7, 9, 5, 6, 1, 8, 2, 4 }; selectionSort(array, 9, evensFirst); printArray(array, 9); return 0; } |
The above snippet produces the following result:
2 4 6 8 1 3 5 7 9
As you can see, using a function pointer in this context provides a nice way to allow a caller to “hook” their own functionality into something you’ve previously written and tested, which helps facilitate code reuse! Previously, if you wanted to sort one array in descending order and another in ascending order, you’d need multiple versions of the sort routine. Now you can have one version that can sort any way the caller desires!
Note: If a function parameter is of a function type, it will be converted to a pointer to the function type. This means
1 |
void selectionSort(int *array, int size, bool (*comparisonFcn)(int, int)) |
can be equivalently written as:
1 |
void selectionSort(int *array, int size, bool comparisonFcn(int, int)) |
This only works for function parameters, not stand-alone function pointers, and so is of somewhat limited use.
Providing default functions
If you’re going to allow the caller to pass in a function as a parameter, it can often be useful to provide some standard functions for the caller to use for their convenience. For example, in the selection sort example above, providing the ascending() and descending() function along with the selectionSort() function would make the caller’s life easier, as they wouldn’t have to rewrite ascending() or descending() every time they want to use them.
You can even set one of these as a default parameter:
1 2 |
// Default the sort to ascending sort void selectionSort(int *array, int size, bool (*comparisonFcn)(int, int) = ascending); |
In this case, as long as the user calls selectionSort normally (not through a function pointer), the comparisonFcn parameter will default to ascending.
Making function pointers prettier with type aliases
Let’s face it -- the syntax for pointers to functions is ugly. However, type aliases can be used to make pointers to functions look more like regular variables:
1 |
using ValidateFunction = bool(*)(int, int); |
This defines a type alias called “ValidateFunction” that is a pointer to a function that takes two ints and returns a bool.
Now instead of doing this:
1 |
bool validate(int x, int y, bool (*fcnPtr)(int, int)); // ugly |
You can do this:
1 |
bool validate(int x, int y, ValidateFunction pfcn) // clean |
Using std::function
An alternate method of defining and storing function pointers is to use std::function, which is part of the standard library <functional> header. To define a function pointer using this method, declare a std::function object like so:
1 2 |
#include <functional> bool validate(int x, int y, std::function<bool(int, int)> fcn); // std::function method that returns a bool and takes two int parameters |
As you see, both the return type and parameters go inside angled brackets, with the parameters inside parenthesis. If there are no parameters, the parentheses can be left empty. Although this reads a little more verbosely, it’s also more explicit, as it makes it clear what the return type and parameters expected are (whereas the typedef method obscures them).
Updating our earlier example with std::function:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
#include <functional> #include <iostream> int foo() { return 5; } int goo() { return 6; } int main() { std::function<int()> fcnPtr{ &foo }; // declare function pointer that returns an int and takes no parameters fcnPtr = &goo; // fcnPtr now points to function goo std::cout << fcnPtr() << '\n'; // call the function just like normal return 0; } |
Note that you can also type alias std::function:
1 2 |
using ValidateFunctionRaw = bool(*)(int, int); // type alias to raw function pointer using ValidateFunction = std::function<bool(int, int)>; // type alias to std::function |
Type inference for function pointers
Much like the auto keyword can be used to infer the type of normal variables, the auto keyword can also infer the type of a function pointer.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
#include <iostream> int foo(int x) { return x; } int main() { auto fcnPtr{ &foo }; std::cout << fcnPtr(5) << '\n'; return 0; } |
This works exactly like you’d expect, and the syntax is very clean. The downside is, of course, that all of the details about the function’s parameters types and return type are hidden, so it’s easier to make a mistake when making a call with the function, or using its return value.
Conclusion
Function pointers are useful primarily when you want to store functions in an array (or other structure), or when you need to pass a function to another function. Because the native syntax to declare function pointers is ugly and error prone, we recommend using std::function. In places where a function pointer type is only used once (e.g. a single parameter or return value), std::function can be used directly. In places where a function pointer type is used multiple times, a type alias to a std::function is a better choice (to prevent repeating yourself).
Quiz time!
1) In this quiz, we’re going to write a version of our basic calculator using function pointers.
1a) Create a short program asking the user for two integer inputs and a mathematical operation (‘+’, ‘-‘, ‘*’, ‘/’). Ensure the user enters a valid operation.
1b) Write functions named add(), subtract(), multiply(), and divide(). These should take two integer parameters and return an integer.
1c) Create a type alias named ArithmeticFunction for a pointer to a function that takes two integer parameters and returns an integer. Use std::function.
1d) Write a function named getArithmeticFunction() that takes an operator character and returns the appropriate function as a function pointer.
1e) Modify your main() function to call getArithmeticFunction(). Call the return value from that function with your inputs and print the result.
Here’s the full program:
![]() |
![]() |
![]() |
I was told that it is good practice to avoid divisions where possible, especially in iterative processes, because they create an overhead. (division takes about 3x longer then multiplication?)
If that is true, then this:
could be optimized like this:
`(x % 2) == 0` doesn't perform a division, every optimizer should convert this to `(x & 1) == 0` (If the least significant bit is set, the number is odd, otherwise it's even).
Compiling your's and Alex' function with clang 11.0.1 -O3 and decompiling it back to C++ using Ghidra 9.2 yields
I'm not expecting you to understand how these functions work. The point is that neither is performing division.
I'm surprised that the output differs at all, I expected this function to be so simple that it doesn't matter how your write it.
The output for your code is interesting in that there are no jumps in it. No matter what the input is, the same instructions are executed. I'd consider this a good thing, but I don't know enough about CPUs to tell if this might be what makes your function slower.
Here's a benchmark comparing your function to Alex' and one that I've written to better understand the problem
https://quick-bench.com/q/Aozz3zGW7XMHGd4CH2EBPVkwzYk
This is a function I'd optimize for readability, not performance. I'd go for either my solution or a modification of your's
I'd only optimize this function if necessary, that is, everything else has been optimized already, and with consideration to that target platform/CPU.
Please let me know if you find `evensFirstKurtNascar()` easier to understand than `evensFirstAlex()`. If so, I'll update the lesson, because I'm not a fan of Alex' solution with all those repetitions.
Hi
The division 3/4 returns answer 0. I tried to add float
float divide(int x, int y)
{
return static_cast<float> (x / y);
}
using ArithmeticFunction = std::function<float(int, int)>;
But it still gives answer 0
please explain
double divide(int x, int y)
{
return static_cast<double> (x) / y;
}
using ArithmeticFunction = std::function<double(int, int)>;
This solves the issue.
Thanks
this code gives me this warning:
the address of 'int foo()' will never be NULL [-Waddress]
and prints 1.
is this because a compiler config or something?
Hi, here's my code. I would appreciate feedback.
This looks good to me, but don't forget to #include <limits> for std::numeric_limits. (It might compile fine for you, but not someone else). I'd also put type aliases at the top, but that's more of a style preference than an issue.
Otherwise this is pretty much identical to the provided solution.
why to use function pointers to design a basic calculator when we can simply use a switch statement?pls clarify my doubt
In case some wants the non-std::function solution, I succeeded writing it with function pointer:
Main.cpp
cheers ;)
Favor return values over out-parameters.
Simply replace the type alias in the quiz's solution with
That's all you need to do to remove the `std::function`.
I first tried this way with C++11
But I couldn't resolve these compiler errors:
0:'ArithmFunction' : symbol cannot be used in a using-declaration
1: missing type specifier - int assumed
2: 'return' : cannot convert from 'int (__cdecl *)(int,int)' to 'int'
Meaning I can't use "using" with pointer type?
I suppose this is now possible in other C++ versions.
Still could do it with an *& out-parameter ... it seems reasonable to use it this way too
That's strange, because it works fine for me in C++ 11. There shouldn't be any issue using
type with using...
1. Error
If I use "int first{ getUserInput() };",
It will crash with C2220 and error 80070002
C2220 and error 80070002 is due to not referencing "first" and "second".
Just use std::cout << first << second << oper; to reference them and avoid the mistake
2. Question
A. For the getArithmeticFunction, am I right to say that std::function<int(int,int)> is a function-pointer type?
B. Are function pointers the only way that you can return a function?
C. When I return the add function, why do I not return it as add()? Why do I not need the brackets?
3. Error
std::cout << getArithmeticFunction(oper); is not the answer for 1e.
4. Feedback
Spelling Error, "Arithemetic".
"ArithmeticFunction fcn{ getArithemeticFunction(op) };"
5. Error
I tried to use the trycatchthrow in later chapters but I gave up after too many bad attempts.
1. This is not a crash. This is a compiler error. The compiler is reporting an error in your code.
2A. `std::function` is a type that wraps a function pointer or callable object. It's not a function pointer itself, but everyone should understand you when you call `std::function` a function pointer.
2B. You can't return "a function", but you can return a function pointer, an object that wraps a function pointer, or a callable object.
2C. `add()` would attempt to call `add()`, but you don't want to call `add()`. If you add an ampersand, `&add`, it's clearer that you're taking the address of a function and didn't just forget to add parentheses.
3. Why would it?
4. Thanks
5.
1. Sorry, mistaken terminology. Compiler error.
2A. I'm slightly more confused with the wrapping terminology.
2B. Ah, I get it. Functions cannot be returned but function pointers can. Thanks.
3. This is my erroneous Train of Thought. I thought std::cout could print out the function pointer. However, that is not possible.
4. It's still in the example.
5. Redoing.
2A. "Wrapping" means building something around another something to make that other something easier. eg. `std::array` wraps a C-style array.
4. Thanks for double-checking, I must have forgotten to save last time.
if (std::cin.fail())
{
std::cin.clear();
std::cin.ignore(32767, '\n');
}
1. Question
int (*fcnPtr3)(int){ &hoo }; // okay
What is the (int) for?
2. Feedback
Perhaps, you might want to caption each example?
E.g. 7.8-2-(28/11/20) means chapter 7.8, example 2, last changed on 28/11/20
The problem is if a student refers to an example, which example are they referring to?
Additionally, it would help to "factorise" your examples and you can easily keep track of how many examples you have and change examples anytime you want.
You can add the change log into the comments.
I remembered there was an Enum example that you changed earlier due to it having values assigned.
@a is the return type, @b is the parameter. There can be more than 1 parameter.
Thanks nascar
1. Feedback. Maybe you could change l-value to L-value? It's clearer that way as a left hand side value.
Hi,
Why do we need to pass functions as parameters using pointers but not the functions themselves? I am a little confused since functions have global scope so we can access them even inside another function. Thank you
Consistency note: In the quiz parts (1d) and (1e), the header text uses getArithmeticFunction(), but the actual code solutions use getArithmeticFcn()
For some reason, I have to enter the first integer twice before starting normal functionality. If I replace line 12 and line 13, nothing happens when I run the program.
An unrelated question from the lesson, but is there any way (aside from the boost libraries) to represent a function of any type in say, a map?
A random example:
Void pointers can technically do this, but it's not a very good solution.
Void pointers can't do this, function pointers can't be converted to void pointers.
Boost can't do anything that you can't do manually. Which feature of boost are you talking about in particular?
Ah silly me, I assumed you could since the syntax didnt give me any warnings in VScode but I never actually compiled a test to see if it worked or not.
From what I've seen online from researching the issue people have mentioned the boost::any type.
If it helps any at all (perhaps I'm thinking about a solution the wrong way), the reason I need this functionality is I'd like to create a generic Menu class for any console program I create, whose instances can display something like this for example:
Choose an option:
[0] Go back
[1] Explore
[2] Set up camp
Instead of displaying this and having to manually handle input for every option in every program that uses the Menu class, I'd rather associate a function to call with each option (along with any args needed I suppose) in a Menu instantiation. This would be easy if the functions were all the same signature, but they could be any function doing anything, one might displayMenu() another menu, while another might add something to the player's inventory.
In a dynamically typed language such as Python, this is trivial to implement.
Here's a short example showing a dictionary of strings and functions:
`boost::any` is `std::any`, but that's not going to help you, because you need to know the type when you go to call the function.
All of your python functions have the same signature, I don't see what's stopping you from doing exactly this in C++.
What the functions do doesn't matter as long as their signatures are identical. If the signatures are different, you can write a wrapper function for your functions. Lambdas (anonymous functions) (later in this chapter) make this very straightforward.
The Python example was just to show that I didn't have to specify the type when using the function in objects. I could have gotten arguments from the user as well as the function and called it using any type (string, float, whatever) that supports those operators, not just some magic number ints.
I didn't think of wrapping the functions (especially using lambdas as wrappers), I'll try it out, thanks!
For some reason, I have to input the first integer twice to start normal functionality. If I exchange lines 12 and 13, nothing happens when I run it. Any replies would be highly appreciated.
If you call `std::cin.ignore()` and there's nothing in the input stream yet, it will prompt for input, which is then discarded right away. Perform error handling after extraction, not before.
Okay got it. Thanks. Excuse me for posting my question in someone else's comment. I mistakenly did that. I tried to delete it but I want able to. So better introduce an option to delete comments like you added the option to edit comments. Good work by the way.
how functions executing in runtime ?
i mean how cpu getting function and executing some functions
Long time no see!
I completed the quiz. I was wondering though, how would I proceed without the alias? What if there was no
at all?
I've tried to put a function pointer inside the function parameters, but it didn't go well. Any tips?
Thanks again :)
Don't do it. Anyway
Also a neat way of replacing this line:
would be:
Just a small thing I thought of :D
"Unlike fundamental types, C++ will implicitly convert a function into a function pointer if needed (so you don’t need to use the address-of operator (&) to get the function’s address). However, it will not implicitly convert function pointers to void pointers, or vice-versa."
Was reading an advanced codebase today, and encountered a function pointer initialized from a function identifier using the address-of operator. This confused the hell out of me since I had the idea the function identifier was itself already a pointer to the function, while in reality function identifiers are _implicitly converted to pointers_ in the context of function pointers. Well, my misunderstanding was born on this page. It may be worthwhile to reorganize this chapter a little. Start by introducing initialization of a function pointer with &funct_name, then say 'in fact, most compilers will implicitly convert the function identifier to its address, so the ampersand can be neglected'.
All compilers support `foo` and `&foo` to initialize function pointers, this is standard behavior. `&foo` was neglected in this lesson, I updated the lesson to make this the preferred syntax. Thanks for pinpointing the lesson that caused your misunderstanding.
I think i got a little confused. Does std::function used to store and define just functions or functions pointers or both?
In what context does it apply in the examples and quizes here?
`std::function` can store all callable things
But in the quiz, it's being used to store a function pointer, right?
Correct. A function pointer falls under the category of "callable things".
I'm trying to put function pointers to member functions in a map, I've read to Chapter 13 but haven't found a way. I tried a few variations of "this->" below, but no luck.
This approach works when it's not in a class, but as soon as it is, it doesn't.
After hours this is what I came up with that works. I have no idea about the scope, functionality or if it could be made more plyable... but it works.
Regardless of all things, I'm still not clear on how to init a map in the constructor :-/
You don't need to initialize the map in the constructor, you can initialize it at its declaration
You can use `std::function` for cleaner syntax and to make `options` work with callable objects
Don't use `const char*` unless you have a reason to, `std::string_view` is safer and more versatile
In line 12 and 13 you're looking up the key "foo" twice. That's unnecessary, you can save the found element from the first lookup
>>Note: If a function parameter is of a function type, it will be converted to a pointer to the function type.
Does that sentence above mean we can use implicit function dereference when we have a function parameter which is of a function
type? Because "bool (*comparisonFcn)(int, int)" is already a pointer to the function type, why did you say, "it will be converted to a pointer to the function type."? The sentence above somehow sounds vague.
can be equivalently written as:
-----------------------------------------------------------------------------------
2)I remember in the 'introduction to standard algorithms (iterators), we have the sort function that uses a 'compare' function as a function parameter, do they use the function pointer concept behind the scenes?
3) can function pointers be used as a return value of another function?
1)
are usually different types, but not when used as function parameters. The first is the type of a function, the second is a function pointer. When they're used as function parameters, they're the same.
2) Standard functions use templates, which means you can pass in any type. Templates are covered later.
3) Yes, this is included in the quiz
>>
Shouldn't it be 'assign function foo to function pointer fncPtr'?
>> I found that we could use address-of operator (&) before the name of the function, is this correct?as the result is the same.
There's no assignment there at all. I updated the comment, thanks!
For regular functions, `foo` and `&foo` is the same. For member functions (covered later), you have to use `&foo`, so I recommend using `&foo` even for regular functions.