Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the difference between different ways of passing a function as an argument to another function?

I have the situation where one function calls one of several possible functions. This seems like a good place to pass a function as a parameter. In this Quoara answer by Zubkov there are three ways to do this.

int g(int x(int)) { return x(1); }
int g(int (*x)(int)) { return x(1); }
int g(int (&x)(int)) { return x(1); }
...
int f(int n) { return n*2; }
g(f); // all three g's above work the same

When should which method be used? What are there differences? I prefer the simplest approach so why shouldn't the first way always be used?

For my situation, the function is only called once and I'd like to keep it simple. I have it working with pass by pointer and I just call it with g(myFunc) where myFunc is the function that gets called last.

like image 954
northerner Avatar asked Oct 04 '19 23:10

northerner


People also ask

What is the difference between passing arguments by arguments and passing arguments by reference?

It's a way how to pass arguments to functions. Passing by reference means the called functions' parameter will be the same as the callers' passed argument (not the value, but the identity - the variable itself). Pass by value means the called functions' parameter will be a copy of the callers' passed argument.

What is the difference between function with passing argument and without passing argument?

A function with argument, as in function(something) is to return a value after processing within the function. A function with no argument, eg function(), is to perform a task with no value returned. In this case, the function acts like a procedure.

What is the difference between a function and an argument?

The values that are declared within a function when the function is called are known as an argument. The variables that are defined when the function is declared are known as parameters. These are used in function call statements to send value from the calling function to the receiving function.


1 Answers

Expanding on L.F.'s comment, it's often better to eschew function pointers entirely, and work in terms of invocable objects (things which define operator()). All of the following allow you to do that:

#include <type_traits>

// (1) unrestricted template parameter, like <algorithm> uses
template<typename Func>
int g(Func x) { return x(1); }

// (2) restricted template parameter to produce possibly better errors
template<
    typename Func,
    typename=std::enable_if_t<std::is_invocable_r_v<int, Func, int>>
>
int g(Func x) { return std::invoke(x, 1); }

// (3) template-less, trading a reduction in code size for runtime overhead and heap use
int g(std::function<int(int)> x) { return x(1); }

Importantly, all of these can be used on lambda functions with captures, unlike any of your options:

int y = 2;
int ret = g([y](int v) {
    return y + v;
});
like image 52
Eric Avatar answered Nov 10 '22 06:11

Eric