【问题标题】:How to search a char in a char array in if condition statement如何在if条件语句中搜索char数组中的char
【发布时间】:2017-10-30 21:28:45
【问题描述】:

是否有任何功能可以帮助我更轻松地完成以下操作?

char ch = '+';
if (( ch == '+') || (ch == '-') || (ch == '*'))
{
    //do something
}

由于必须在我的代码中多次检查这一点,我希望有类似的方法

char arr ={'+','-','*'};
if (ch in arr)
{
    //do something 
}

【问题讨论】:

  • 是什么让你觉得现有的代码不“高效”?您能否向我们展示您的基准测试表明它是您的代码中的一个瓶颈,以及您的研究表明它可以改进吗?
  • 现在,如果你想要这样让你的代码更易于维护和表达,那是完全合理的:)
  • 您可以使用 std::findstd::any_of 之类的东西,但正如 @BoundaryImposition 所说,如果这会比您的第一个版本在性能上获胜,我会感到惊讶。
  • @BoundaryImposition 有问题的不是运行时间,而是打字时间。在实际代码中,我必须在七个字符之间进行检查,并执行三次。正如你所说,我只是想知道是否有某种方法可以使代码更易于维护和编写:)

标签: c++ if-statement char


【解决方案1】:

对于这种特定情况,您可以将布尔表达式包装在您自己的自定义函数中:

bool isOperator(char ch) {
    return ( ch == '+') || (ch == '-') || (ch == '*');
}

这将减少其余代码中的冗余,因为现在您可以这样做了

if(isOperator(ch))

【讨论】:

    【解决方案2】:

    试试这个

    #include <algorithm>
    
    int main() {
       char arr[] ={'+','-','*'};
       char ch = '-';
       if(std::find(arr, arr+sizeof(arr)/sizeof(char), ch) - arr < sizeof(arr)/sizeof(char)){
       //do anything 
       }
       return 0;
    }
    

    【讨论】:

    • 硬编码的3 可以改进,你不觉得吗?
    • 我已经编辑了我的答案,可以吗?谢谢你告诉我。
    • 我会考虑使用std::array,这样你就可以简单地使用.size()而不是sizeof技巧。
    • 当然你是对的,但我试图回答这个特定的问题,我试图使用 char arr[] 就像问题一样。我是对的还是什么?我想在这里有用。谢谢:D
    【解决方案3】:

    对我来说,乍一看,这是一个集合查找:这个元素中的任何一个等价于这组元素是否包含这个元素。因此:

    if ((std::set<char> {'a','b','c'}).count(x) > 0) {
        // ...
    }
    

    See it on Coliru

    【讨论】:

      【解决方案4】:

      如果您的数组也是,这会使any 成为编译时构造。如果范围是任意的,我真的想不出一种更优化的方法。

      我选择重载==,因为它看起来比并排传递参数更好。

      #include<iterator>
      
      template<typename Iter>
      class any
      {
      public:
          using value_type = typename std::iterator_traits<Iter>::value_type;
      
          constexpr any(Iter begin, Iter end) : begin{begin}, end{end} {}
          template<typename T, size_t N>
          constexpr any(T (&arr)[N]) : any{arr, arr + N} {}
      
          constexpr bool operator==(const value_type& v)
          {
              return compare(v, begin);
          }
      private:
          Iter begin, end;
          constexpr bool compare(const value_type& v, Iter it)
          {
              return it != end && (v == *it || compare(v, it + 1));
          }
      };
      
      template<typename T, size_t N>
      any(T (&)[N]) -> any<T*>;
      
      template<typename T, typename Iter>
      constexpr bool operator==(const T& t, any<Iter> a)
      {
          return a == t;
      }
      

      这会产生一个漂亮的格式

      static_assert('+' == any("+-*"), "Failure!");
      
      constexpr char ops[] = {'+', '-', '*'};
      char c = '/';
      if(c == any(ops))
          do_stuff(c);
      

      说明

      using value_type = typename std::iterator_traits<Iter>::value_type;
      

      是将类型Iter取消引用的别名为value_type

      template<typename T, size_t N>
      any(T (&)[N]) -> any<T*>;
      

      deduct the typeany,没有明确的模板参数。

      return it != end && (v == *it || compare(v, it + 1));
      

      是递归检查范围是否已经耗尽,如果没有,则检查值是否等于当前元素。

      请注意,any("+-*") 中有 4 个字符,最后一个是 '\0'

      【讨论】:

        【解决方案5】:

        你可以写一个函数来生成等价于

        的代码
        if (( ch == '+') || (ch == '-') || (ch == '*'))
        

        具有更好的用户语法。


        template <typename X>
        bool any(const X&) noexcept
        {
            return false;
        }
        
        template <typename X, typename T, typename... Ts>
        bool any(const X& x, const T& curr, const Ts&... rest) noexcept
        {
            return x == curr || any(x, rest...);
        }
        

        用法:

        if(any(ch, '+', '-', '*')) { /* do something */ }
        

        by this godbolt.org comparison 所示,这是一个零成本抽象的示例。

        在 C++17 中,您可以使用 fold expression:

        template <typename X, typename... Ts>
        bool any(const X& x, const Ts&... rest)
        {
            return ((x == rest) || ...);
        }
        

        如果您想多次重复使用相同的比较值而不重复自己,您可以创建 any 的“curried”版本,它首先绑定要检查的参数,然后在后续调用中进行比较。

        template <typename... Ts>
        auto bound_any(const Ts&... xs)
        {
            return [xs...](const auto& x)
            {
                return ((x == xs) || ...);
            };
        }
        

        用法:

        auto is_op = bound_any('+', '-', '*');
        if(is_op(ch)) { /* do something */ }
        

        这里是a godbolt.org comparison

        【讨论】:

        • 你的函数的名字不是很好,而且你也不允许在代码的多个部分中不重复自己这样做(这似乎是OP所关心的)跨度>
        • 现在更好,但最终过度设计。 :)
        • @BoundaryImposition:为什么说这是过度设计?
        • 用一个复杂的函数替换三个== 和两个||环境(甚至还不是标准),是过度设计的。举个例子:上面的 OP 完全不知道你的建议是如何工作的。这很聪明,但不实用。
        • 我也认为这主要是过度设计,但有两件事可以挽救它:(1)原版“设计不足”(重复,容易出错)和(2)c ++ 17是可读和简洁的。因此,我认为答案只是信息丰富且富有洞察力。谢谢。
        【解决方案6】:

        在这种情况下,您可以使用:

        if ( std::strchr("+-*", ch) )
        

        strchr 函数来自 #include &lt;cstring&gt;,如果在字符串中找不到该字符,则返回一个空指针。

        【讨论】:

        • 为什么使用 C 函数?可以使用std::array&lt;char, size&gt; arr{ /* ... */ }; if (std::find(arr.cbegin(), arr.cend(), '+') == arr.cend() || /* ... */) { }
        • @6EQUJ5 因为它简单、清晰、简洁。我不会因为其他语言也提供相同的功能而对完全可用的功能有偏见
        • @6EQUJ5 std::strchr 是 C++ 标准强制要求的,并未弃用。它与上述文档规定的任何其他功能一样,都是 C++ 的一部分
        • @6EQUJ5:您建议的替代方案甚至比原始代码更加混乱和冗长,更不用说 MM 的建议了。
        • 我想我应该注意,如果ch 可能是空字符,我的解决方案将不起作用
        猜你喜欢
        • 1970-01-01
        • 2014-01-02
        • 2016-03-17
        • 2016-07-14
        • 2014-10-15
        • 2013-07-12
        • 2018-12-15
        • 2015-07-24
        • 1970-01-01
        相关资源
        最近更新 更多