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*
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:
std::function
instead of a function pointer for the callback.
std::function
is more general and powerful representation of a callable.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.#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