58 lines
2.3 KiB
Plaintext
58 lines
2.3 KiB
Plaintext
To configure an algorithm with a function in {cpp}, you can use one of the following techniques:
|
|
|
|
* A function pointer (see S5205 that explains why it is a bad idea)
|
|
* An ``++std::function++``
|
|
* A template argument
|
|
|
|
How do you select between an ``++std::function++`` and a template argument?
|
|
|
|
``++std::function++`` offers the most flexibility. You can store them in a variable, in a container (as ``++std::map<string, std::function<void(void)>>++`` for instance... This flexibility is provided by type erasure: A single ``++std::function++`` can wrap any kind of functor, as long as the signature is compatible. It also comes with a cost: Due to this type erasure, a compiler will typically not be able to inline a call to a ``++std::function++``.
|
|
|
|
|
|
Template parameters, on the other hand, are less flexible. Each functor has its own type, which prevents storing several of them together even if they all have compatible signatures. But since each template instance knows the type of the functor, calls can be inlined making this a zero-cost abstraction.
|
|
|
|
|
|
As a conclusion, if the functor can be known at compile-time, you should prefer using a template parameter, if it has to be dynamic, ``++std::function++`` will give you greater flexibility.
|
|
|
|
|
|
This rule detects function parameters of type ``++std::function++`` that would probably benefit from being replaced by a template parameter. It does so by looking if the functor is only called inside the function, or if it participates in other operations.
|
|
|
|
|
|
== Noncompliant Code Example
|
|
|
|
----
|
|
using Criterion = std::function<bool(DataPoint const&)>;
|
|
void filter(DataSet* data, Criterion criterion) { // Noncompliant
|
|
for (auto &dataPoint : data) {
|
|
if (criterion(dataPoint)) {
|
|
data.markForRemoval(dataPoint);
|
|
}
|
|
}
|
|
}
|
|
----
|
|
|
|
|
|
== Compliant Solution
|
|
|
|
----
|
|
template<class Criterion>
|
|
void filter(DataSet* data, Criterion criterion) { // Compliant
|
|
for (auto &dataPoint : data) {
|
|
if (criterion(dataPoint)) {
|
|
data.markForRemoval(dataPoint);
|
|
}
|
|
}
|
|
}
|
|
----
|
|
|
|
|
|
== Exceptions
|
|
|
|
This rule ignores virtual functions, that don't work well with templates.
|
|
|
|
== See
|
|
|
|
* https://github.com/isocpp/CppCoreGuidelines/blob/036324/CppCoreGuidelines.md#t49-where-possible-avoid-type-erasure[{cpp} Core Guidelines T.49] - Where possible, avoid type-erasure
|
|
|
|
|