В некотором коде тестирования есть вспомогательная функция, подобная этой:
auto make_condiment(bool salt, bool pepper, bool oil, bool garlic) {
// assumes that first bool is salt, second is pepper,
// and so on...
//
// Make up something according to flags
return something;
};
который по существу создает something
на основе некоторых флагов bool
ean.
Что меня беспокоит, так это то, что значение каждого bool
жестко закодировано в именах параметров, что плохо, потому что на месте вызова трудно вспомнить, какой параметр что означает (да, IDE, вероятно, может полностью устранить проблему, показывая эти имена при завершении табуляции, но все же...):
// at the call site:
auto obj = make_condiment(false, false, true, true); // what ingredients am I using and what not?
Поэтому я хотел бы передать один объект, описывающий настройки. Кроме того, просто объединяя их в объект, например. std::array<bool,4>
.
Вместо этого я хотел бы включить такой синтаксис:
auto obj = make_smart_condiment(oil + garlic);
который сгенерирует тот же obj
, что и предыдущий вызов make_condiment
.
Эта новая функция будет:
auto make_smart_condiment(Ingredients ingredients) {
// retrieve the individual flags from the input
bool salt = ingredients.hasSalt();
bool pepper = ingredients.hasPepper();
bool oil = ingredients.hasOil();
bool garlic = ingredients.hasGarlic();
// same body as make_condiment, or simply:
return make_condiment(salt, pepper, oil, garlic);
}
struct Ingredients {
public:
enum class INGREDIENTS { Salt = 1, Pepper = 2, Oil = 4, Garlic = 8 };
explicit Ingredients() : flags{0} {};
explicit Ingredients(INGREDIENTS const& f) : flags{static_cast<int>(f)} {};
private:
explicit Ingredients(int fs) : flags{fs} {}
int flags; // values 0-15
public:
bool hasSalt() const {
return flags % 2;
}
bool hasPepper() const {
return (flags / 2) % 2;
}
bool hasOil() const {
return (flags / 4) % 2;
}
bool hasGarlic() const {
return (flags / 8) % 2;
}
Ingredients operator+(Ingredients const& f) {
return Ingredients(flags + f.flags);
}
}
salt{Ingredients::INGREDIENTS::Salt},
pepper{Ingredients::INGREDIENTS::Pepper},
oil{Ingredients::INGREDIENTS::Oil},
garlic{Ingredients::INGREDIENTS::Garlic};
Однако у меня такое чувство, что я заново изобретаю велосипед.
Есть ли лучший или стандартный способ выполнения вышеизложенного?
Может быть, есть шаблон проектирования, который я мог бы/должен использовать?
std::map
может быть лучшим решением. - person Mansoor   schedule 08.07.2021auto obj = make_smart_condiment(Ingrediant{.oil = true, .garlic = true});
- person NathanOliver   schedule 08.07.2021return flags & INGREDIENTS::Garlic
, возможно, будет более читабельным, чемreturn (flags / 8) % 2;
- person Drew Dormann   schedule 08.07.2021|
, а не+
, так как это намного лучше соответствовало бы классическим аргументам битового флага, даже если семантика технически больше соответствует+
. - person Frank   schedule 08.07.2021+
будет давать неверные результаты, если обе стороны будут иметь одинаковый ингредиент, а|
будет работать правильно. - person interjay   schedule 08.07.2021hasXxx
можно было бы свести к одной функции шаблона? - person DS_London   schedule 08.07.2021+
в порядке в операции? Разве это не вызывает проблему, которую выделил @interjay? - person Enlico   schedule 08.07.2021hasXXX()
требуется много усилий. По моему опыту, этот тип проблемы обычно решается с битовыми операциями, и тогда вам нужен толькоenum
!my_ingredients | Ing::Pepper
комбайны.my_ingredients & Ing::Pepper
тесты. - person Drew Dormann   schedule 08.07.2021INGREDIENTS
вместоIngredients
? Если это так, я буду рад удалить весь этот код. - person Enlico   schedule 08.07.2021a | b
объединяетa
иb
.(a & b) == b
проверяет, есть ли уa
все вb
. Еслиb
— это всего лишь один ингредиент, вы можете сократить его доa & b
. - person Drew Dormann   schedule 08.07.2021