Опираясь на Предложение Конрада об использовании типов политики , если ваши алгоритмы требуют параметров во время построения, вы можете справиться с этим чисто, потребовав, чтобы любой класс Policy
имел вложенный тип, называемый Params
, и затем предоставьте конструктор внутри fancy_algorithm<Policy>
, который принимает аргумент этого типа и передает его в содержащийся Policy
объект:
template <typename Policy>
class fancy_algorithm : private Policy {
public:
typedef typename Policy::Params Params; // Need to redeclare :(
explicit fancy_algorithm(Params params = Params()) : Policy(params) {}
};
Все соответствующие параметры должны быть упакованы в один объект типа Policy::Params
.
Класс Policy
всегда создается с одним аргументом типа Policy::Params
. Для работы с классами политик, которые (могут) не требовать параметров, предоставьте конструктор по умолчанию (или используйте неявно объявленный) в Params
, а не в Policy
. Таким образом, используя значение по умолчанию для конструктора fancy_algorithm<Policy>
, как указано выше, мы включаем удобную конструкцию по умолчанию для fancy_algorithm<Policy>
всякий раз, когда Policy::Params
имеет конструктор по умолчанию (т. Е. Когда Policy
не требует никаких параметров) , Безопасность не теряется: если у Policy::Params
отсутствует конструктор по умолчанию (что указывает на то, что некоторые параметры обязательны ), любая попытка создать объект по умолчанию fancy_algorithm<Policy>
не удастся во время компиляции.
Пример:
struct multiply_by_params {
multiply_by_params(int x /* = 42 */) : _x(x) {} // See bottom
int get() const { return _x; } // Or, just make multiply_by a friend
private:
int _x;
};
struct multiply_by {
typedef multiply_by_params Params;
multiply_by(Params p) : _x(p.get()) { /* Other initialisation */ }
// Other code implementing the strategy (e.g. an operator()())
...
private:
int _x;
};
fancy_algorithm<multiply_by> a(69); // Always compiles
fancy_algorithm<multiply_by> b; // Compiles iff /* = 42 */ is uncommented