更好的方式来说x == Foo :: A || x == Foo :: B || x == Foo :: C || ...?

Meh*_*dad 20 c++ c++03

假设我有一堆众所周知的值,就像这样(但const char *只是一个例子,它可能会更复杂):

const char *A = "A", *B = "B", *C = "C", *D = "D", *E = "E", *F = "F", *G = "G";
Run Code Online (Sandbox Code Playgroud)

现在让我们说如果某个表达式的结果位于其中的一个子集中,我希望以特定方式运行:

if (some_complicated_expression_with_ugly_return_type == A ||
    some_complicated_expression_with_ugly_return_type == C ||
    some_complicated_expression_with_ugly_return_type == E ||
    some_complicated_expression_with_ugly_return_type == G)
{
    ...
}
Run Code Online (Sandbox Code Playgroud)

我发现自己经常输入这种东西,我想要一个简写.

如果语言是Python,我可以很容易地说:

if some_complicated_expression_with_ugly_return_type in [A, C, E, G]:
    ...
Run Code Online (Sandbox Code Playgroud)

有一种众所周知的,可移植的方式让我在C++ 03中表达同样的东西吗?

请注意,返回类型本身很难看(几乎和lambda表达式的返回类型一样难看),所以我当然不希望将它存储在局部变量中.

但返回类型并没有必须匹配的常量的-例如,如果返回类型是std::string,这将不会是隐式转换为const char *,但operator ==将是比较完美的罚款.

到目前为止,我所拥有的最佳解决方案是:

const char *items[] = { A, C, E, G };
if (std::find(items, items + sizeof(items) / sizeof(*items),
              some_complicated_expression_with_ugly_return_type)
    != items + sizeof(items) / sizeof(*items))
{
    ...
}
Run Code Online (Sandbox Code Playgroud)

但它非常难看.有没有更好的方法,这也适用于非POD?

Pet*_*ker 27

如果你有C++ 11:

auto res = some_complicated_expression_with_ugly_return_type;
if (res == A
    || res == C
    || res == E
    || res == G) {
}
Run Code Online (Sandbox Code Playgroud)

如果没有,您仍然可以使用模板函数消除类型声明:

template <class T>
bool matches(T t) {
    return t == A || t == C || t == E || t == G;
}

if (matches(some_complicated_expression_with_ugly_return_type)) {
}
Run Code Online (Sandbox Code Playgroud)

  • 我的回答也提供了一个适用于C++ 03的解决方案. (2认同)

MvG*_*MvG 23

您可以将当前最佳解决方案纳入模板:

template<class A, class B, size_t n>
inline bool is_in(const A &a, B (&bs)[n]) {
  return std::find(bs, bs + n, a) != bs + n;
}
Run Code Online (Sandbox Code Playgroud)

你可以使用它

X items[] = { A, C, E, G };
if (is_in(some_complicated_expression_with_ugly_return_type, items))
  …
Run Code Online (Sandbox Code Playgroud)

  • @Mehrdad,哪种返回类型?你的表达中的那个我在这里视为一个黑盒子,所以我在这里几乎无能为力.你明确指出的唯一类型是`X`,你比较的值的类型.正如您已经使用名称引用这些值,我假设这些值至少有一些相当短的类型名称. (3认同)

bdo*_*lan 12

你可以使用switch:

switch (some_complicated_expression_with_ugly_return_type) {
  case A: case C: case E: case G:
    // do something
  default:
    // no-op
}
Run Code Online (Sandbox Code Playgroud)

注意,这仅适用于整数和枚举类型.

对于更复杂的类型,您可以使用C++ 11 auto,或者使用C++ 03,boostBOOST_AUTO:

auto tmp = some_complicated_expression_with_ugly_return_type;
// or
BOOST_AUTO(tmp, some_complicated_expression_with_ugly_return_type);

if (tmp == A || tmp == C || tmp == E || tmp == G) {
  // ...
}
Run Code Online (Sandbox Code Playgroud)


Ros*_*ith 9

(编辑:用虚拟类型制作我的原始技巧不起作用,我在测试中被一次幸运的事故误导了.让我们再试一次......)

有了几个辅助模板,您可以为这种情况编写一般解决方案:

template <typename T1> class Matcher {
public:
    explicit Matcher(T1 t1): val(t1), flag(false) {}
    template <typename T2> Matcher& operator()(T2 t2)
        { flag |= val == t2; return *this; }
    operator bool() const { return flag; }
private:
    T1 val;
    bool flag;
};
template <typename T1> Matcher<T1> match(T1 t1) { return Matcher<T1>(t1); }

// example...
string s = whatever;
if (match(s)("foo")("bar")("zap")) { do_something(); }
Run Code Online (Sandbox Code Playgroud)

您可以根据需要匹配任意数量的参数.