Better way to say x == Foo::A || x == Foo::B || x == Foo::C || …?

前端 未结 8 598
醉酒成梦
醉酒成梦 2021-02-07 03:23

Let\'s say I have a bunch of well-known values, like this (but const char * is just an example, it could be more complicated):

const char *A = \"A\"         


        
相关标签:
8条回答
  • 2021-02-07 03:45

    You could factor your current best solution into a template:

    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;
    }
    

    which you can use like

    X items[] = { A, C, E, G };
    if (is_in(some_complicated_expression_with_ugly_return_type, items))
      …
    
    0 讨论(0)
  • 2021-02-07 03:49

    If not switch, maybe something like this, I didn't use it, but may be a draft to something working?

    template <class ReturnType>
    bool average(ReturnType expression, int count, ...)
    {
      va_list ap;
      va_start(ap, count); //Requires the last fixed parameter (to get the address)
      for(int j=0; j<count; j++)
        if(expression==va_arg(ap, ReturnType))
          return true;
        return false
      va_end(ap);
    }
    
    0 讨论(0)
  • 2021-02-07 03:57

    If you have C++11:

    auto res = some_complicated_expression_with_ugly_return_type;
    if (res == A
        || res == C
        || res == E
        || res == G) {
    }
    

    if not, you can still eliminate the type declaration by using a template function:

    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)) {
    }
    
    0 讨论(0)
  • 2021-02-07 03:58

    Expressions of the type

    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)
    {
        ...
    }
    

    are quite common in code (well, a pre-computed expression is anyway). I think the best you can do for readability is pre-compute the expression and keep it as is.

    ugly_return_type x = some_complicated_expression_with_ugly_return_type;
    if (x == A ||
        x == C ||
        x == E ||
        x == G)
    {
        ...
    }
    

    Developers are used to this type of syntax. This makes it a whole lot easier to understand when someone else is reading your code

    It also expresses what you want perfectly. There's a reason this type of syntax is so widely used in existing code - because other alternatives are worse for readability.

    Of course, you could wrap the condition in a function, but only if it's reusable and it logically makes sense (besides the point IMO).

    0 讨论(0)
  • 2021-02-07 03:59

    C++11:

    template<typename T1, typename T2>
    bool equalsOneOf (T1&& value, T2&& candidate) {
       return std::forward<T1>(value) == std::forward<T2>(candidate);
    }
    
    template<typename T1, typename T2, typename ...T>
    bool equalsOneOf (T1&& value, T2&& firstCandidate, T&&...otherCandidates) {
       return (std::forward<T1>(value) == std::forward<T2>(firstCandidate))
         || equalsOneOf (std::forward<T1> (value), std::forward<T>(otherCandidates)...);
    }
    
    if (equalsOneOf (complexExpression, A, D, E)) { ... }
    

    C++03:

    template<typename T, typename C>
    bool equalsOneOf (const T& value, const C& c) { return value == c; }
    
    template<typename T, typename C1, typename C2>
    bool equalsOneOf (const T& value, const C1& c1, const C2& c2) {
        return (value == c2) || equalsOneOf (value, c1);
    }
    
    template<typename T, typename C1, typename C2, typename C3>
    bool equalsOneOf (const T& value, const C1& c1, const C2& c2, const C3& c3) {
        return (value == c3) || equalsOneOf (value, c1, c2);
    }
    
    template<typename T, typename C1, typename C2, typename C3, typename C4>
    bool equalsOneOf (const T& value, const C1& c1, const C2& c2, const C3& c3, const C4& c4) {
        return (value == c4) || equalsOneOf (value, c1, c2, c3);
    }
    
    template<typename T, typename C1, typename C2, typename C3, typename C4, typename C5>
    bool equalsOneOf (const T& value, const C1& c1, const C2& c2, const C3& c3, const C4& c4, const C5& c5) {
        return (value == c5) || equalsOneOf (value, c1, c2, c3, c4);
    }
    
    // and so on, as many as you need
    
    0 讨论(0)
  • 2021-02-07 04:02

    You could use a switch:

    switch (some_complicated_expression_with_ugly_return_type) {
      case A: case C: case E: case G:
        // do something
      default:
        // no-op
    }
    

    This only works with integer and enum types, note.

    For more complex types, you can use C++11's auto, or for C++03, boost's BOOST_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) {
      // ...
    }
    
    0 讨论(0)
提交回复
热议问题