Хотя Boost.Parameters забавно, он страдает (к сожалению) из-за ряда проблем, среди которых коллизия заполнителей (и необходимость отлаживать причудливые ошибки препроцессоров / шаблонов):
BOOST_PARAMETER_NAME(p1)
Создает _p1
заполнитель, который вы потом используете.Если у вас есть два разных заголовка, объявляющих один и тот же заполнитель, вы получите конфликт.Не весело.
Существует гораздо более простой (как концептуальный, так и практический) ответ, основанный на шаблоне Builder
, в некотором смысле это идиома именованных параметров .
вместоуказав такую функцию:
void f(int a, int b, int c = 10, int d = 20);
Вы указываете структуру, для которой вы будете переопределять operator()
:
- конструктор, используемый для запроса обязательных аргументов (не строгов идиоме именованных параметров, но никто не сказал, что вы должны следовать ему вслепую), а для необязательных значений установлены значения по умолчанию
- каждому необязательному параметру присваивается сеттер
Как правило,он объединяется с Chaining , которая заключается в том, что установщики возвращают ссылку на текущий объект, так что вызовы могут быть объединены в одну строку.
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()
- нет), это должно привести к аналогично эффективному коду по сравнению с «обычным» вызовом функции.