首页 > 解决方案 > 如何将几个布尔标志包装到结构中,以使用方便的语法将它们传递给函数

问题描述

在一些测试代码中有一个这样的辅助函数:

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基于一些boolean 标志建立的。

我担心的是每个参数的含义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};

但是,我有一种重新发明轮子的感觉。

标签: c++design-patternsinterfacec++17flags

解决方案


如果您想使用枚举作为标志,通常的方法是将它们合并operator |并检查它们operator &

#include <iostream>

enum Ingredients{ Salt = 1, Pepper = 2, Oil = 4, Garlic = 8 };

// If you want to use operator +
Ingredients operator + (Ingredients a,Ingredients b) {
    return Ingredients(a | b);
}

int main()
{
    using std::cout;
    cout << bool( Salt & Ingredients::Salt   ); // has salt
    cout << bool( Salt & Ingredients::Pepper ); // doesn't has pepper

    auto sp = Ingredients::Salt + Ingredients::Pepper;
    cout << bool( sp & Ingredients::Salt     ); // has salt
    cout << bool( sp & Ingredients::Garlic   ); // doesn't has garlic
}

注意:如果你混合喜欢,当前代码(只有operator +)将不起作用。|+(Salt|Salt)+Salt


也可以使用enum class,只需要定义操作符


推荐阅读