c++callback

Using callback functions


I am following a tutorial series and there's a lesson about callback functions featuring a simple calculator. I am inept at programming, but I do understand pointers and functions.

The tutorial demonstrated a simple case with two functions accepting (int, int) and a function that accepts function pointers as arguments, but I decided to take my own spin on it and pass an array of double and two size_t variables (to mark the beginning and end of the array) as arguments to the addition and a subtraction functions.

I tried to pass three arguments to all functions and a function pointer to the "operation" function. I expected the program to add or subtract all the numbers in an array depending on the choice the user makes.

#include <iostream>
#include <cmath>

double add(double[], size_t, size_t);
double subtract(double[], size_t, size_t);

int main()
{
    double numbers[] { 1.3, 2.0, 3.5};
    size_t start = 0;
    size_t end = std::size(numbers);
    double(*operation)(double(*), double numbers[], size_t start, size_t end); // a function pointer
    char choice = '0';  // a char variable for the choice of operation
    double result;  // result of the operation for the output

    std::cin >> choice; // input

    if(choice == '+')
    {
        result = operation(add, numbers, &start, &end); // passing the addition function as an argument to the operation function
    }
    if(choice == '-')
    {
        result = operation(subtract, numbers, &start, &end);
    }
    std::cout << result << std::endl;   // output
}

double add(double numbers[], size_t *start, size_t *end)    // add all numbers in the array
{
    double result = 0;

    for(int i = *start; i < *end; i++)
    {
        result += numbers[i];
    }
    return result;
}

double subtract(double numbers[], size_t start, size_t end) // subtract the following numbers from the first one in the array
{
    double result = 0;

    for(int i = start; i < end; i++)
    {
        result -= numbers[i];
    }
    return result;
}

double operation(double(*op)(double, size_t, size_t), double numbers[], size_t start, size_t end)
{
    return op(numbers, start, end); // the function that accepts two functions as arguments
}

The error I get from the compiler is:

funcpointerscalc.cpp: In function ‘int main()’:
funcpointerscalc.cpp:20:28: error: cannot convert ‘double (*)(double*, size_t, size_t)’ {aka ‘double (*)(double*, long unsigned int, long unsigned int)’} to ‘double*’ in argument passing
   20 |         result = operation(add, numbers, &start, &end);
      |                            ^~~
      |                            |
      |                            double (*)(double*, size_t, size_t) {aka double (*)(double*, long unsigned int, long unsigned int)}
funcpointerscalc.cpp:24:28: error: cannot convert ‘double (*)(double*, size_t, size_t)’ {aka ‘double (*)(double*, long unsigned int, long unsigned int)’} to ‘double*’ in argument passing
   24 |         result = operation(subtract, numbers, &start, &end);
      |                            ^~~~~~~~
      |                            |
      |                            double (*)(double*, size_t, size_t) {aka double (*)(double*, long unsigned int, long unsigned int)}
funcpointerscalc.cpp: In function ‘double* add(double*, size_t*, size_t*)’:
funcpointerscalc.cpp:37:12: error: invalid type argument of unary ‘*’ (have ‘double’)
   37 |     return *result;
      |            ^~~~~~~
funcpointerscalc.cpp: At global scope:
funcpointerscalc.cpp:40:9: error: ambiguating new declaration of ‘double* subtract(double*, size_t, size_t)’
   40 | double* subtract(double numbers[], size_t start, size_t end)
      |         ^~~~~~~~
funcpointerscalc.cpp:5:8: note: old declaration ‘double subtract(double*, size_t, size_t)’
    5 | double subtract(double[], size_t, size_t);
      |        ^~~~~~~~
funcpointerscalc.cpp: In function ‘double* subtract(double*, size_t, size_t)’:
funcpointerscalc.cpp:48:12: error: invalid type argument of unary ‘*’ (have ‘double’)
   48 |     return *result;
      |            ^~~~~~~
funcpointerscalc.cpp: In function ‘double operation(double (*)(double, size_t, size_t), double*, size_t, size_t)’:
funcpointerscalc.cpp:53:15: error: cannot convert ‘double*’ to ‘double’ in argument passing
   53 |     return op(numbers, start, end);
      |               ^~~~~~~
      |               |
      |               double*


Solution

  • The other answer (by @463035818_is_not_an_ai) already explains the reason for your compilation errors and how to fix them.

    In this answer I attempt to offer an alternative way (better IMHO) to implement the same functionality using more modern C++ mechanisms:

    1. Use std::function instead of a function pointer for the callback. std::function is more general and powerful representation of a callable.
    2. Use std::span instead of a raw array with start and end markers. This is exactly what a std::span is for - a lightweight abstraction of a continous range of elements.
    3. Use a ranged-based for-loop instead of one with a manual index.
    #include <iostream>
    #include <span>
    #include <functional>
    
    double add(std::span<double> numbers) {
        double result{ 0 };
        for (auto num : numbers) result += num;
        return result;
    }
    
    double subtract(std::span<double> numbers) {
        double result{ 0 };
        for (auto num : numbers) result -= num;
        return result;
    }
    
    double operation(std::function<double(std::span<double> op)> op, std::span<double> numbers) {
        return op(numbers); 
    }
    
    int main() {
        double numbers[]{ 1.3, 2.0, 3.5 };
        std::cout << "add: " <<      operation(add,      std::span<double>(numbers)) << "\n";
        std::cout << "subtract: " << operation(subtract, std::span<double>(numbers)) << "\n";
    }
    

    Output:

    add: 6.8
    subtract: -6.8
    

    Live demo