Search

7.8 — Function Pointers

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:

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:

At some point in your programming career (if you haven’t already), you’ll probably make a simple mistake:

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:

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++:

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:

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):

One common mistake is to do this:

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:

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:

The second way is via implicit dereference:

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.

All 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 function sorts without affecting the rest of the sorting code.

Here is our selection sort routine from a previous lesson:

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:

And here’s our selection sort routine using the ascending() function to do the comparison:

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:

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:

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:

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 version 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

can be equivalently written as:

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 callers 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:

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 typedef or type aliases

Let’s face it -- the syntax for pointers to functions is ugly. However, typedefs can be used to make pointers to functions look more like regular variables:

This defines a typedef called “validateFcn” that is a pointer to a function that takes two ints and returns a bool.

Now instead of doing this:

You can do this:

Which reads a lot nicer! However, the syntax to define the typedef itself can be difficult to remember.

In C++11, you can instead use type aliases to create aliases for function pointers types:

This reads more naturally than the equivalent typedef, since the name of the alias and the alias definition are placed on opposite sides of the equals sign.

Using a type alias is identical to using a typedef:

Using std::function in C++11

Introduced in C++11, 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:

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:

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.

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. Unfortunately, type inference won’t work for function parameters (even if they have default values), so its use is somewhat limited.

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 you use typedefs (or in C++11, std::function).

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.

Show Solution

1b) Write functions named add(), subtract(), multiply(), and divide(). These should take two integer parameters and return an integer.

Show Solution

1c) Create a typedef named arithmeticFcn for a pointer to a function that takes two integer parameters and returns an integer.

Show Solution

1d) Write a function named getArithmeticFunction() that takes an operator character and returns the appropriate function as a function pointer.

Show Solution

1e) Modify your main() function to call getArithmeticFunction(). Call the return value from that function with your inputs and print the result.

Show Solution

Here’s the full program:

Show Solution

2) Now let’s modify the program we wrote in quiz 1 to move the logic out of the getArithmeticFcn and into an array.

2a) Create a struct named arithmeticStruct that has two members: a mathematical operator char, and an arithmeticFcn function pointer.

Show Solution

2b) Create a static global array of arithmeticStruct named arithmeticArray, initialized with each of the four arithmetic functions.

Show Solution

2c) Modify getArithmeticFcn to loop through the array and return the appropriate function pointer.

Show Solution

Here’s the full program:

Show Solution

7.9 -- The stack and the heap
Index
7.7 -- Default arguments

397 comments to 7.8 — Function Pointers

  • Alex A

    Hi again all, and hope everyone had a merry christmas!
    so on this decided to try and use std::function as opposed to typedef for the quiz as it was recommended in the guides (hope not wrong to do so?) took me a little while to get my head around the proper declaration (i think) for them. can someone look over and make sure all the below is correct as there are obviously no solutions for me to check it against?

    • Hi!

      * Line 31: Initialize to a 0 value
      * @getArithmenticFunction: Missing return
      * You're using the same name style for variables, function and types. This will lead to confusion.

      Your use of @std::function is corrent. Even when using @std::function, a type alias can be helpful to allow faster changes to the function signature.

      • Alex A

        thanks for the help Nas.

        on naming styles, what would you recommend? the simplest solution would seem to be add a suffix of either v, f or t to the end to make it clear would that be advisable?

        • UpperCamelCase for types
          lowerCamelCase for functions
          flHungarianNotation type prefixes for variables ( https://en.wikipedia.org/wiki/Hungarian_notation#Examples )

          Is what I use. Along with an additional prefix for member/constant/static variables.
          Here's a rather boring example of my code, though, enough to give you an idea what it looks like https://gitlab.com/Cre3per/td_json5/blob/master/src/json5/parser/CLexer.cpp

  • magaji::hussaini

    my soln...

    • magaji::hussaini

      Ah! @line 33 & 108:
      should be uniform initialisation ofcourse.
      Sorry I forgot that!

    • > Ah!
      Yep

      * Line 2: Prefer C++ over macros. Macros are prone to errors that can be difficult to get behind (Lesson 2.9).

      * Line 5: Type aliases with the using-keyword have a more intuitive syntax than typedef.

      * Line 6 is unnecessary
      * You're using the same naming convention for variables, functions and types. This will lead to confusion.
      * Line 23: Use constexpr for compile-time constants.
      * Line 23, 24: There's no reason for these to be globals. Move them into @getArithmeticFunction
      * Line 37: You should go figure that out. There's something wrong with your compiler (settings).
      * Line 44, 70: while-statements want a boolean. Use while(true). (Yes, true is 1. This is about style.)
      * Line 82: Use switch when you're checking for a limited set of values. This allows the compiler to use better optimization.
      * @getInput and @getOp are mostly equivalent. Try to add another function to avoid duplicate code.
      * Line 108: You have an alias for that type

      * Line 109: There's no need to dereference

      • magaji::hussaini

        Oh thank you so much especially @line5 because the typedef is confusing me that why I ignore using it.I will apply the changes and post it again.
        Also, any idea about the compiler settings I am using g++, I will also check man g++ command for more...
        Thanks alot.

      • magaji::hussaini

        Hi!
        @2 : aren't macros part of C++?
        Ofcourse they are prone to errors ONLY if misused or used in excess.
        Questions:
        1. Are macros depricated in C++?
        If Yes what will be the alternatives of __LINE__, __TIME__,...) in C++?
        2. Why did cpprefrence include PREPROCESSOR?
          https://en.cppreference.com/w/cpp/preprocessor
        There are dozens of macros provided by C++ for testing, debugging, etc.
        I dont think @2 is problematic if all I want is subtitution.

        • > aren't macros part of C++?
          Yes they are. But they're a language for the preprocessor, not for the compiler. I don't count that as C++.

          > Are macros depricated in C++?
          No. But a lot of things that required macros in the past can now be done in C++ (Using be definition from above).

          > Why did cpprefrence include PREPROCESSOR?
          Because there still are things that can't be done without it.

          > ONLY if misused or used in excess
          That goes for all rules and conventions. If you use them where you shouldn't, at some point you'll use them where you can't.

  • hnsdgvefeqg

    Why is the alias in the parenthesis with the asterisk? why not after all the parenthesis?

  • Clapfish

    Hi guys!

    Code for feedback - is there anything I can improve on here? (short of using std::function)

    • Hi Clapfish!

      When you have a limited set of values you want to check for (eg. chars, enums), use a switch-statement instead of if-else-if. Switch-statements can be optimized by the compiler (via jump tables).

      * Line 63: Only initialize to a non-null value if you have a reason to do so. Initializing to anything apart from null-values leads the reader to believe that this value is used for something.

      * Line 66: Good use of constexpr
      * Line 68-71: You already declared @math_array as an array of @MathStruct. You don't have to write out "MathStruct" in any of these lines.

      You need an extra pair of curly brackets because of how @std::array works.
      * Line 80: This can make your code hard to debug if execution should ever get here. It's better to return a nullptr (and add an assert (Lesson 7.12a)).
      * Line 89: Uniform initialization

      Although your code is simpler, I'd like to give a shout out to @std::find_if

      The third argument to @std::find_if is a lambda function (A function without a name). You should learn about those, they aren't covered on learncpp.

      This quiz asked for an array and learncpp doesn't cover @std::map. You should learn about @std::map, it's ideal for a scenario like this.

      • Clapfish

        Hi nascardriver!

        Many thanks for this!

        Based on your first suggestion, I've re-written the getOperator() function as follows:

        Is it okay to omit 'default: break;' here, or should that always be included as best practice?
        I assume this function was what you were referring to - is it now as efficient as it can be? I was also wondering about the input variable initialisation being inside the loop (and thus destroyed/recreated each time the user enters invalid input) - would it be better practice / more efficient to declare this before the loop?
        ---

        * Line 68-71: You already declared @math_array as an array of @MathStruct. You don't have to write out "MathStruct" in any of these lines.

        Thanks for clearing that up! After seeing Alex's solution I tried removing 'MathStruct' from each line but it was giving me an error, regarding too many initialisers - the extra curly brackets worked a treat. Could you explain what it is about std::array that causes this?
        ---

        Can't believe I missed a uniform initialisation! :)
        ---

        Huge thanks for all the extra info; duly noted as things to bear in mind and look into when I'm done with learncpp.com. Can you recommend further reading when that time comes, which would cover topics such as these (if possible, in a similar manner to learncpp.com)?

        For now, I tried your code suggestions and it worked (when I switched my #include <array> to <map>), apart from:

        I had to take out the initialisation of 'found' from the if statement to make it work, otherwise I was getting a bunch of errors. Is that because I haven't included something?

        • > Is it okay to omit 'default: break;' here
          It's fine

          > is it now as efficient as it can be?
          I don't see anything that needs improvement.

          > I was also wondering about the input variable initialisation being inside the loop (and thus destroyed/recreated each time the user enters invalid input)
          It won't get destroyed and created every cycle.
          This could happen with custom types (struct/class), but the cost of an initialization should be the same as a reassignment. Even with custom types, your compiler probably will probably re-use the memory of the old object instead of reserving new memory.

          > Could you explain what it is about std::array that causes this?
          @std::array doesn't have a constructor that accepts an array, instead, it uses aggregate initialization (just like structs). The first pair of curly brackets are the initialization brackets for @std::array, inside those we can initialize @std::array's members, which is nothing but a c-style array. To initialize an array we need another set of curly brackets. The c-style array's elements are @MathStructs, which need another set of curly brackets to initialize.

          > Can you recommend further reading
          Nope. Alex has a list with things to add to learncpp. I'm assuming you'll be done with the current lessons before new ones show up. You can check back from time to time to see if anything changed. Until then you'll have to find another resource or learn on your own.

          > I had to take out the initialisation of 'found' from the if statement to make it work
          Initializers in an if-statement are a c++17 feature. Make sure you enable c++17 in your compiler settings. -std=c++17 for compilers with a gcc interface.

          • Clapfish

            Brilliant, thank you!

            > Nope. Alex has a list with things to add to learncpp. I'm assuming you'll be done with the current lessons before new ones show up. You can check back from time to time to see if anything changed. Until then you'll have to find another resource or learn on your own.

            ...reinforcing the fact that learncpp.com is such a valuable resource, including your valuable contribution to it. I've already started playing around with @std::map and @std::find_if, looking into their declarations even (though delving into that 'behind-the-scenes' syntax still feels a bit messy and complex), in an attempt to understand their functionality better.

            In a way it's quite reassuring to feel that I'm in the best place available to learn C++, and I'll continue to contribute too as best I can along the way and, as you say, keep coming back.

            Which actually brings me back to another question that I've thought about a couple of times; namely, how do you keep so up to date with all the lesson comments? I assume you have some way of being notified by the site whenever a new comment comes in on any page? If so, is that a special privilege or is that something anyone could request/set-up somehow?

            • > I assume you have some way of being notified by the site whenever a new comment comes in on any page? If so, is that a special privilege or is that something anyone could request/set-up somehow?
              I'm not associated with learncpp, I don't have any more access than anyone else. Learncpp is powered by WordPress, which offers an API that can be used to search for new comments. I've written a node script ( https://gitlab.com/Cre3per/wpnotify (Code's not nice, it'd need small tweaks to properly work on windows)) that notifies me about new comments.

              • Clapfish

                Ah cool, thanks for sharing! Maybe when I've gotten through the tutorial here I'll try to figure out how to implement that or something similar for myself. For the time being I wouldn't really know where to start... but I have downloaded a copy :)

  • saj

    Hi!, Without using typedef, can this be possible:

    because i'm getting two error messages on this line:
    functions.h|15|error: expected unqualified-id before ')' token
    functions.h|15|error: expected initializer before 'getArithmeticFunction'

  • Mike

    Only because it came up in a job interview - this seems to be a natural lead-in to lambda expressions (7.8a - Lambda expressions)?
    I get the impression, from reading, around that they're a fairly well-established programming concept that haven't been given much spotlight on here. Is that not the case, or is there just another more common way of doing what they achieve?

  • Harsh Verma

    Hey, i want to get the input from the user about array length and its value after that i want user to make decision whether he wants to sort the array or not. There is my code and what should i do in that case....... Please Help me...............

    • @takingInput dynamically allocated memory but the variable holding the pointer to it is lost at the end of the function resulting in a memory leak. @takingInput should return the array and it's size to the caller (@main) from where it can be passed to @sorting.

      • Harsh Verma

        I return array and it's size in @takingInput but nothing happen in @sorting, when i called sorting. I also want user to enter it's choice about how he want sort the array in given functions. So please help me with suitable example and explanation. Thank you

        • Make sure you understood lesson 1.1, 1.4a, 5.3 and 7.1-7.4a.
          Post you current code and comment on the lines you're having problems with. Explain what exactly you want to do (eg. by posting sample output/input), what you have tried to achieve it, and why it didn't work.

  • Gizmo

    I created my getArithmeticFcn() a little differently. Instead of using two functions to get the operand and the function pointer separately, I combined the two into one function.

    This is my function for program 1:

    This is the modified version for program 2:

    The reason I am changing the original value for operand is so I can use it when I print the equation.

    Are my versions of the function acceptable to use, or would they slow the program down more than if I used two functions to get the operand and function pointer separately? Also, would it be better if I used a pointer to change the operand instead of a reference in this case?

    • > I combined the two into one function
      That's generally a bad thing to do. Your code should be modular. If you now want to get the operator from somewhere else you'll have to modify @getArithmeticFunction. And if you do so, you won't be able to get the operator from @stdin anymore. Splitting code apart increases readability, reusability and maintainability.

      > would they slow the program down more than if I used two functions
      They're most likely faster than a two-function solution, because they do the exact same except that they are using 1 less call. The effect is so small that it should be ignored in favor of the three points mentioned above. Leave low-level optimization to the compiler unless the change doesn't decrease code quality or is easy to apply.

      > would it be better if I used a pointer
      That's up to you.
      Pro: For the caller it's obvious that the argument will be modified.
      Con: The caller could pass a nullptr

  • mashal

    how we use this !!!
    typedef int (*arithmeticFcn)(int, int); // its take two int

    arithmeticFcn getArithmeticFcn(char op) // this Char ! and the type take two int ?? what going on ?
    {
        switch (op)
        {
        default: // default will be to add
        case '+': return add;
        case '-': return subtract;
        case '*': return multiply;
        case '/': return divide;
        }
    }

    int main()
    {
        int x = getInteger();
        char op = getOperation();
        int y = getInteger();

        arithmeticFcn fcn = getArithmeticFcn(op);
        std::cout << x << ' ' << op << ' ' << y << " = " << fcn(x, y) << '\n';

        return 0;
    }

  • TC

    Hi Alex,

    No sure that if someone already points out this because I haven't read the entire comments. Isn't that the function name validateFcn is supposed to follow typedef?

    Best regard,
    TC
      

    This defines a typedef called “validateFcn” that is a pointer to a function that takes two ints and returns a bool.

  • CrashTheRed

    Hello, I'd like to inquire about a problem I found while trying to make a permanent input cpp so I could reuse it instead of having to redo it every single time.
    So my problem is when entering different data types I would have to declare int x or char x or whatever the data type, but for the most part, it's the same while(true) loop with the same cin.fail(), cin.clear() and what not, and I'd rather find an alternative for this as I don't like the idea of copy pasting the entirety of it multiple times just so I could change int x to char x, to double x, etc etc. Any help would be greatly appreciate :)

    • Move the reusable code into a separate function

      If that's still too much repetition, you'll have to have a look at templates (Chapter 13).

  • Jörg

    Can you only create a function which returns a pointer to a function with typedef? I've tried to create one with std::function but it doesn't seem to work out for me.

  • part 1 working well with new pch.h header:

    • Hi Nigel!

      * Line 17, 68: Uniform initialization
      * @main, @getArithmeticFcn: Missing return value

      I like to have type definitions at the to of the file where they're easily found. I don't think there's anything wrong with having them somewhere in-between functions though.

  • Michi

    Hello, I have a question regarding 2c.
    Of course there are many solutions but according to the chapter on 7.4a wouldn't it be more appropriate to have a function declaration like so:

    The caller would not receive an invalid reference because the arithmeticArray has global file scope and isn't it better to return struct by reference instead of by value?

    • Alex

      arithmeticFcn is a pointer to a function, so getArithmeticFcn() is returning a pointer to the appropriate function, not a struct. Returning the pointer by reference is unnecessary.

  • Arush

    Hello Alex,

    Awesome tutorials! But one thing, if you use reinterpret_cast I think you should make a lesson on all the different kinds of castings like const_cast, static_cast, etc.

    Thanks for the tutorials!

  • Arumikaze

    Hello! I have completed the calculator question and I would like some feedback on my code. Also while I was coding, I noticed I didn't have to put "#include <limits>" or various other headers when compiling. I also noticed it when I was using std::swap in previous questions, I didn't have to type "#include <utility>" or "#include <algorithm>". Why does the code still compile and still work without these headers? Thank you as always.

  • Louis Cloete

    At 2 b)

    Why is the array not const?

  • Louis Cloete

    I got tired to have to go back to look up the syntax for

    and remembering all that should be done to clear std::cin after invalid input, so I wrote routines for myself doing that in a separate code file. I then included the function prototypes in a header. Now I just need to #include my header and include the .cpp file in my project. Here they are for anybody interested, with an example of their use in my answer to Quiz 1.

    InputValidationRoutines.cpp:

    InputValidationRoutines.h:

    main.cpp:

    Feel free to use the code!

    Regards,
    Louis

  • Hao

    Thank you so much for the explanation on this topic, and everything else of course! I am feeling much much more comfortable writing function pointers now! As well as the uniform initialization method! Wonder if there is a chapter on function pointers within a class, cause the syntax always confuses me.

    • Hi Hao!

      Use @std::function from <functional>, it's a lot easier than regular function pointers in my opinion.

      The syntax of @std::function is

      where nullptr is your function pointer.

      You should also read lesson 8.8.

      References
      * Lesson 8.8 - The hidden “this” pointer
      * @std::function - https://en.cppreference.com/w/cpp/utility/functional/function

      • Hao

        Thank you for your reply, narscardriver! still a little bit confusing, like what's that CMyClass* doing at the spot of parameters? I will check chapter 8.8 and maybe maybe other articles about it as well!

  • Ethan Partida

    I tried doing the first project using std::function, is there anything I did wrong?

    • Hi Ethan!

      * Line 10, 27, 74: Initialize your variables
      * Line 15: This only needs to run when an error occurred, not when an invalid operator was entered
      * Line 16, 32: Use @std::numeric_limits<std::streamsize>::max() instead of 32767
      * @getInputInt and @getInputChar are very similar, you can split them up into more functions to reduce repetition
      * @getArithmeticFunction has no reason to receive a function as parameter
      * Line 64-67: Unnecessary assignments
      * Line 78: Missing line feed
      * Your indention is inconsistent, your editor most likely has a feature to format the document for you

      • Ethan Partida

        Hi nascardriver, thank you very much for your advice it is very much appreciated! I fixed my arguments to getArithmeticFunction and its working great! I just have two questions, at line 15 I included when an invalid operator was entered so that the function would not pass an invalid operator to the caller, would you recommenced doing this a different way? My other question was what do you mean by missing line feed?

        • > line 15
          Scenario:
          User enters 'm'
          @std::cin.clear() is called
          But, the stream was never in a failed state, there was no reason to call @std::cin.clear(), this should be handled differently.

          > what do you mean by missing line feed?
          Your program exits without telling the terminal to progress to the next line, this will look bad. Change it to

  • Sagar

    how can we return fuction poiner from a function without using typedef?
    Is that even possible?

    • nascardriver

      Hi Sagar!

      See @Cumhur's question and my reply here http://www.learncpp.com/cpp-tutorial/78-function-pointers/comment-page-4/#comment-324446

  • DecSco

    I tried using uniform initialisation on a std::array:

    but it fails, with the error "too many initializers for 'std::array<arithmeticStruct, 4u>'.
    Why? Substituting 'std::array>arithmeticStruct,4> arithmeticArray' with 'arithmeticStruct arithmeticArray[]' makes it work just fine.

    • nascardriver

      Hi DecSco!

      See Frederico's comment and replies to it further down: http://www.learncpp.com/cpp-tutorial/78-function-pointers/comment-page-4/#comment-317170

      • DecSco

        Thank you! With double braces, it worked, so even though the reasons are not a hundred percent clear, I'll remember that for non-POD arrays.
        EDIT: I mean, the reason for different behaviour is pretty clear, as it's simply implemented differently. The reason WHY the difference between std::array and C-style arrays is allowed is what remains somewhat unclear.

  • Cumhur

    how do we form return 'type' without typedef?

    This is not valid somehow.

    • nascardriver

      Hi Cumhur!

      The syntax for this is weird, prefer a typedef, using alias, or @std::function.

  • KKR

    • nascardriver

      Hi KKR!

      @ob is the name of the parameter to @pf. It's not a variable and not accessible from anywhere. If you want to pass the operator you need to add is as a parameter of @show.

      You're calling @Operation::add which returns an @Operation. So you're passing an @Operation to a function that expects a function pointer.

      After changing those things, it still won't work, because member functions are different from normal functions. See lesson 8.8 - The hidden “this” pointer.
      Use @std::function to make your life easier.

      * Don't use 'using namespace'
      * Use uniform initialization

      • KKR

        Thanks nascardriver!!

        In what way is the behaviour of the member function different from a normal function in this case? What exactly is going wrong when I try to pass the function 'A.add(B)' as argument to 'show' function using a function pointer? Why do I need to use std::function?

        Thanks!

        • nascardriver

          > In what way does the behaviour of the member function different from a normal function
          Member functions have a pointer to the object as their first parameter, see lesson 8.8.

          > What exactly is going wrong when I try to pass the function 'A.add(B)' as argument
          When you pass A.add(B) you're not passing the function, you're passing whatever A.add(B) returned.

          > Why do I need to use std::function?
          You don't need to, but using regular function pointers to call member functions results is very ugly code. If you don't have a reason to use regular functions pointers you should use @std::function.

          • KKR

            How to accomplish my purpose without using std::function? I don't have C++11..

            • nascardriver

              You should really get a newer compiler. A lot of features which you shouldn't miss out on have been added in the last 15 years.

              I cannot explain this code to you. If you want an explanation you'll need to wait for someone else.

  • Nick

    Hi all,

    I'm struggling to understand this part here:

    I get the &arith part is pointing to the array element, but I'm not sure how it's working.  I mean, "arith" has not been declared anywhere, but the program runs fine.  Also, I can't figure out the "auto" qualifier after "const".  Is there a lesson I could go back and check again?

    Thanks!

    • nascardriver

      Hi Nick!

      Lesson 4.8 — The auto keyword
      Lesson 6.12a — For-each loops

      @arith isn't a pointer, it's a reference and it's created in the loop's header.

      auto will automatically be replaced with the correct data type.

      • Nick

        HI Nascardriver,

        Thanks for the quick response.

        So this part:

        is shorthand basically saying (For each element in Array arithmericArray)?  

        I'll look at those lessons also.

  • Matt

    I'm starting to struggle to keep things straight in my head at this point, going to have to start going back I think!

    • nascardriver

      Hi Matt!

      Don't worry if you're having trouble with function pointers, I have to peek at an example every time I need one too.
      If you don't need a function pointer for low-level reasons you can use std::function which is way easier.

      General: You're using the same naming for structs, functions and variables. This will get confusing sooner or later.

      Line 85: Avoid globals. You can move this into @getArithmeticFunction since it's not used anywhere else.

      References
      http://en.cppreference.com/w/cpp/utility/functional/function

  • Frederico

    Hello,

    I tried to use a std::array instead of a built in array and it would not let me do it. It gave me a message saying incomplete type is not allowed. I'm not sure why.

    • nascardriver

      Hi Frederico!

      The following code works, I don't know why you need to state the type, hopefully Alex can elaborate. (Your order of arithmeticFcn and char was wrong too).

      • Alex

        > I don’t know why you need to state the type

        I'm not totally sure, but this question came up before. See this comment: http://www.learncpp.com/cpp-tutorial/78-function-pointers/comment-page-3/#comment-290835

    • Alex

      The advantage of using a shared pointer is that it will delete the object when the last reference is gone, whereas a dumb pointer won't. If you have two dynamically allocated objects pointed at each other, It's challenging to have them self-delete with dumb pointers, because there's no way to tell whether the pointer is already dangling or not. There are certainly ways to work around this, by using your own reference counting or management, but using a shared_ptr is so much easier.

  • Benjamin

    Hey Alex,

    just a minor comment:

    In the solution for 2c) you might want to write

    instead. I know it is not important for the point of this lesson, but for consistency with your previous lessons ("use const whereever you don't intend to change a parameter") it might be better.

  • Rex Lucas

    Hi Alex
    I have been studying your code for Quiz 1 (full solution).
    I was wondering how I might modify the code in order to remove the typedef (in other words go back to an "ugly" representation!)

    line 65 is easy enough: replace  

    with  

    but what do I do about the return type at line 47?

    • Rex Lucas

      Hi again Alex
      I checked back at the Q&A for this section.

      Regarding the return type at line 47, I see that (if I want to eliminate typedef) the answer is to replace

      with

      I can see why using typedef is a good idea!

    • Alex

      Yes seriously.

      This is why we use typedefs or other methods to do this. :)

      • Rex Lucas

        Hi Alex
        Although it's not relevant to your quiz question, I thought I would try and construct a pointer, eg fcnptr, to point to the getArithmeticFcn function and then use fcnptr to call the getArithmeticFcn function with fcnptr(op)

        It's easy enough using typedef. However, being masochistic I wanted to do it without! I am having difficulties with this.

        How would I do this?

        • Alex

          I'm not sure. I'm sure there's some logical way to figure it out but I'm not that masochistic. :)

          • Rex Lucas

            Hi Alex
            That's OK - I may be a masochist but I'm not sadistic!
            Happy Christmas and once again thanks for all the great work you are doing here on this fantastic site, especially since I assume you have a day job to do as well!!
            Rex

      • Silviu

        Hello.

        so the
        arithmeticFcn is the alias name and fcn is the pointer ?
        using arithmeticFcn=int(*)(int,int); is this correct ? and then
        arithmeticFcn fcn; is
        int(*fcn)(int,int); am i right ?
        It's a little confusing, in the sort example it's more clear and the other examples.

  • Rex Lucas

    Hi Alex
    Small point. (Unless I completely missed something important!!) you might consider re-writing

    to

    to avoid the thought: ...."why is Alex changing the names of the integer parameters"....!!

Leave a Comment

Put all code inside code tags: [code]your code here[/code]