I've been using a "pattern" to configure C++ class instances via lambdas for a while now and I am looking for:
- an original source & name (I think I read this somewhere, but can't find any online resource unfortunately)
- pitfalls when using the pattern and whether there are means of solving them (I hope this question is not too vague)
The pattern basically works by passing a lambda to the constructor of a class. The class constructor then simply passes the lambda the state to be adjusted.
Example usage
What a users calling code looks like:
Configurable instance([](auto& opts) {
opts.option = true;
});
Pattern
What a class using the "pattern" looks like:
class Configurable {
private:
struct Opts {
/// options that can have sane defaults, should have them
bool option{false};
/// options which do not have sane defaults should be an optional
std::optional<size_t> counter;
} opts;
public:
Configurable(std::function<void(Opts&)> f) {
f(opts);
/// options which are required to be set, can be checked via e.g. an assertion
assert(opts.counter && "[Configurable::Configurable] counter must be set");
}
};
Pros
- Easily extendable with new options without breaking the client code interface (i.e. code can stay the same, but recompilation may be required)
- Value associated with a named parameter (
opts.option = value
) - Partial configurators / combined configurators possible (e.g.
Configurable(juxt(setOptionA(value1), setOptionB(value2)))
wherejuxt
is the juxtaposition, i.e. [f1, ..., fn] combined to be applied to the same argument in sequence)- this in particular is worth gold, when instantiating several instances with the same parameters, which is often required in the codebase I work with
Cons
- Uncommon pattern
- Opts struct may need additional constructor in case of non pod types
- Overhead on classes with no / few parameters to the constructor
auto
vsauto&
in the lambda can lead to no configuration at all, even though everything compiles