Хотя Boost.Parameters забавен, он страдает (к сожалению) от ряда проблем, среди которых коллизия заполнителей (и необходимость отлаживать причудливые ошибки препроцессоров/шаблонов):
BOOST_PARAMETER_NAME(p1)
Создаст заполнитель _p1
, который вы затем будете использовать позже. Если у вас есть два разных заголовка, объявляющих один и тот же заполнитель, возникает конфликт. Не смешно.
Существует гораздо более простой (как концептуально, так и практически) ответ, основанный на шаблоне Builder
, в некоторой степени — это Идиома именованных параметров.
Вместо указания такой функции:
void f(int a, int b, int c = 10, int d = 20);
Вы указываете структуру, в которой вы будете переопределять operator()
:
- конструктор используется для запроса обязательных аргументов (не строго в идиоме именованных параметров, но никто не говорил, что вы должны следовать ему вслепую), а для необязательных устанавливаются значения по умолчанию.
- каждому необязательному параметру дается сеттер
Как правило, он сочетается с цепочкой, которая заключается в том, что сеттеры возвращают ссылку на текущий объект, чтобы вызовы можно было объединить в одну строку.
class f {
public:
// Take mandatory arguments, set default values
f(int a, int b): _a(a), _b(b), _c(10), _d(20) {}
// Define setters for optional arguments
// Remember the Chaining idiom
f& c(int v) { _c = v; return *this; }
f& d(int v) { _d = v; return *this; }
// Finally define the invocation function
void operator()() const;
private:
int _a;
int _b;
int _c;
int _d;
}; // class f
Вызов:
f(/*a=*/1, /*b=*/2).c(3)(); // the last () being to actually invoke the function
Я видел вариант с помещением обязательных аргументов в качестве параметров в operator()
, это позволяет избежать сохранения аргументов в качестве атрибутов, но синтаксис немного страннее:
f().c(3)(/*a=*/1, /*b=*/2);
Как только компилятор встроит все вызовы конструкторов и сеттеров (поэтому они определены здесь, а operator()
нет), это должно привести к такому же эффективному коду по сравнению с «обычным» вызовом функции.
person
Matthieu M.
schedule
18.11.2011