When you want to receive a function as a parameter in a function definition, there are three ways to declare its parameter type:
- A function pointer:
void f(void (*callback)());
- A typed-erased function wrapper such as
std::function
:
void f(std::function<void()> callback);
- A template parameter:
template <class Callback> void f(Callback callback);
Using a function pointer is an inferior solution for the following reasons:
- Only a function pointer can be passed as an argument, while the other options offer the caller more flexibility because they can take more
advanced functors, such as lambdas with some captured state
- The syntax is obscure
- It typically has worse performance than the template parameter solution.
See S5213 for a discussion on choosing between std::function
and a template parameter.
Noncompliant code example
using Criterion = bool (*)(DataPoint const&);
void filter(DataSet& data, Criterion criterion); // Noncompliant
using Callback = void (*)(EventInfo const&);
class Button {
public:
void addOnClick(Callback c) { // Noncompliant
myOnClickHandler = c;
}
private:
Callback myOnClickHandler;
};
Compliant solution
template <class Criterion> // Compliant, uses the more efficient template argument
void filter(DataSet& data, Criterion criterion);
using Callback = std::function<void(EventInfo const&)>;
class Button {
public:
void addOnClick(Callback c) { // Compliant, uses the more flexible std::function
myOnClickHandler = std::move(c);
}
private:
Callback myOnClickHandler;
};