как справиться с ситуацией, когда функция имеет много параметров, а клиентскому коду нужно изменить только несколько из них?

Как не заблудиться в таком случае?
Например, это функция, которая возвращает bool, но принимает 10 параметров:

bool myFunc(bool par1 = true, bool par2 = false, bool par3 = true,
bool par4 = true /* and so on */ ) {}

И скажем, что параметры функции установлены по умолчанию для 90% случаев. Но иногда клиентский код хочет изменить только некоторые из них. Единственный вариант, который я вижу здесь, — это кропотливое копирование всех параметров по умолчанию, пока мы не доберемся до того, который необходимо изменить. Любой шанс вызвать эту функцию таким образом:

bool myVal = myFunc(par10 = true, par20 = false);

Таким образом, любой, кто читает код, знает, что происходит (имена параметров очень длинные, но значимые) с кодом, и, кроме того, когда я изменяю определение функции, мне не нужно будет искать всякий раз, когда она вызывается для обновления параметров по умолчанию?

2

Решение

Есть идиома, которая в меру известна: идиома именованных параметров.

Идея проста:

class Parameters {
public:
Parameters(): _1(true), _2(false), _3(true), _4(true) {}

bool get1() const { return _1; }
bool get2() const { return _2; }
bool get3() const { return _3; }
bool get4() const { return _4; }

Parameters& set1(bool t) { _1 = t; return *this; }
Parameters& set2(bool t) { _2 = t; return *this; }
Parameters& set3(bool t) { _3 = t; return *this; }
Parameters& set4(bool t) { _4 = t; return *this; }

private:
bool _1;
bool _2;
bool _3;
bool _4;
};

bool myFunc(Parameters p);

Тогда клиент может сделать:

result = myFunc(Parameters());

Или же:

result = myFunc(Parameters().set4(false));
11

Другие решения

Посмотри на boost.parameter библиотека.

Используйте эту библиотеку для написания функций и шаблонов классов, которые могут
принимать аргументы по имени:

 new_window("alert", _width=10, _titlebar=false);
smart_ptr<Foo, deleter<Deallocate<Foo> >, copy_policy<DeepCopy> > p(new Foo);

Поскольку именованные аргументы могут передаваться в любом порядке, они особенно полезны, когда функция или шаблон имеют более одного
параметр с полезным значением по умолчанию. Библиотека также поддерживает
выведенные параметры; то есть параметры, идентичность которых может быть
выводится из их типов.

2

Это одна из причин, по которой таких интерфейсов следует избегать. Создайте оболочку для вашего функционала, принимая структуру, которая содержит все параметры. На клиентской стороне создайте конфигурацию по умолчанию (сделайте ее доступной всякий раз, когда вы захотите вызвать функцию; например, в контексте объекта). Всякий раз, когда вы хотите вызвать функцию, скопируйте конфигурацию в другой экземпляр, измените нужные значения и передайте ее в упакованную функцию.

Или, что еще лучше, если возможно, измените сигнатуру функции напрямую, без упаковщиков, чтобы принять агрегированную конфигурацию.

1

Использование можно использовать boost::bind (на C ++ 03) или std::bind (на C ++ 11), чтобы изменить порядок и исправить некоторые параметры вашей функции.

0

Если у вас есть случай, когда некоторые аргументы имеют смысл только в парах, используйте перегруженные функции.

Так, например, вместо (извините, сейчас нет лучшего примера)

// Adds a new TODO. Either this is a low-prio TODO with no defined
// deadline, xor a deadlined TODO for which year, month, day must
// be passed.
void add_todo (std::string description, int year=-1, int month=-1, int day=-1);

делать

void add_todo (std::string description, int year, month, day);

void add_todo (std::string description) {
add_todo(description, -1, -1, -1);
}

таким образом, чтобы обеспечить выполнение одной и только одной из двух возможных сигнатур вызовов.

Конечно, было бы лучше добавить больше структуры, как Date, Но даже тогда я не делайте советую сделать Date «обнуляемый» только ради этого:

void add_todo (std::string description, Date = Date::None); // <-- I wouldn't

скорее

void add_todo (std::string description);
void add_todo (std::string description, Date deadline);

или иногда нет перегрузки и вообще нет настроек по умолчанию

void add_todo (std::string description);
void add_deadlined_todo (std::string description, Date deadline);
0
По вопросам рекламы [email protected]