检查值是否属于某些静态集的最C ++方法是什么?

时间:2018-07-24 10:33:24

标签: c++ set c++14

让我们说我要写这样的东西({1, 3, 7, 42, 69, 550123}集在编译之前就知道了)

int x;
...
if (x == 1 || x == 3 || x == 7 || x == 42 || x == 69 || x == 5550123)
{
  ...
}

该条件看起来很丑,因为每个可能的值都有9个额外的符号(“ || x ==”)。如何用更C ++的方式重写它?

我最好的猜测是:

int x;
...
const std::unordered_set<int> v = {1, 3, 7, 42, 69, 5550123};
if (v.count(x))
{
  ...
}

它的平均复杂度为O(1),有一些内存和时间开销,但看起来仍然很丑。

5 个答案:

答案 0 :(得分:7)

编辑:我刚刚注意到c ++ 14标记。请注意,我对java.sql.Array的实现依赖于C ++ 17。也可以使用递归在C ++ 14中完成,但这涉及更多样板,并且编译速度稍慢。

一个人可以使用模板来生成具有逻辑运算符序列的函数,例如nvoigt的答案中的一个:

Object array = ( (Array) resultOracleStruct.getAttributes()[2]) ).getArray();

也就是说,将一组魔术数字隐藏在一个命名函数的后面可能很有意义:

in

答案 1 :(得分:5)

唯一的干净方法是将其移动到方法上。适当地 Name 方法,您在内部执行的操作并不重要。

bool is_valid_foo_number(int x)
{
    return x == 1
        || x == 3
        || x == 7
        || x == 42
        || x == 69
        || x == 5550123;
}

该方法对我来说已经足够好了,因为我所能看到的只是

if (is_valid_foo_number(input))
{
    // ...
}

如果要更改技术细节(例如,需要使用另一种查找方法的大量有效数字,或者可能是数据库而不是硬编码的值),则应更改方法的内部。

重点是我认为它看起来很丑...因为您需要在查看逻辑的同时对其进行查看。无论如何,您都不必查看这些细节。

答案 2 :(得分:4)

  

如何用更C ++的方式重写它?

建议:为其创建可变参数模板函数,使其具有通用性(不仅适用于int值),还使其具有constexpr;这样,您可以检查集合中值的存在,编译时间。

您标记了C ++ 14,但我首先展示了C ++ 11的递归方式,其中包含一个递归案例和一个基础案例

template <typename T>
constexpr bool is_in_list_11 (T const &)
 { return false; }

template <typename T, T t0, T ... ts>
constexpr bool is_in_list_11 (T const & t)
 { return (t == t0) || is_in_list_11<T, ts...>(t); }

从C ++ 14开始,constexpr函数可能要复杂得多,因此不再需要递归,您可以编写如下内容

template <typename T, T ... ts>
constexpr auto is_in_list_14 (T const & t)
 {
   using unused = bool[];

   bool ret { false };

   (void)unused { false, ret |= t == ts ... };

   return ret;
 }

从C ++ 17开始,您还可以使用auto模板类型和模板折叠,因此功能(如user2079303前面所示)变得非常简单

template <auto ... ts, typename T>
constexpr auto is_in_list_17 (T const & t)
 { return ( (t == ts) || ... ); }

以下是所有版本的完整示例

#include <iostream>

template <typename T>
constexpr bool is_in_list_11 (T const &)
 { return false; }

template <typename T, T t0, T ... ts>
constexpr bool is_in_list_11 (T const & t)
 { return (t == t0) || is_in_list_11<T, ts...>(t); }

template <typename T, T ... ts>
constexpr auto is_in_list_14 (T const & t)
 {
   using unused = bool[];

   bool ret { false };

   (void)unused { false, ret |= t == ts ... };

   return ret;
 }

template <auto ... ts, typename T>
constexpr auto is_in_list_17 (T const & t)
 { return ( (t == ts) || ... ); }

int main ()
 {
   constexpr auto b11a { is_in_list_11<int, 1, 3, 7, 42, 69, 5550123>(7) };
   constexpr auto b11b { is_in_list_11<int, 1, 3, 7, 42, 69, 5550123>(8) };

   constexpr auto b14a { is_in_list_14<int, 1, 3, 7, 42, 69, 5550123>(7) };
   constexpr auto b14b { is_in_list_14<int, 1, 3, 7, 42, 69, 5550123>(8) };

   constexpr auto b17a { is_in_list_17<1, 3, 7, 42, 69, 5550123>(7) };
   constexpr auto b17b { is_in_list_17<1, 3, 7, 42, 69, 5550123>(8) };

   std::cout << b11a << ' ' << b11b << std::endl;
   std::cout << b14a << ' ' << b14b << std::endl;
   std::cout << b17a << ' ' << b17b << std::endl;
 }

答案 3 :(得分:1)

尝试一下:

#include <iostream>
#include <vector>
#include <algorithm>
int main()
{
  std::vector<int> v = {1, 3, 7, 42, 69, 5550123};
  auto is_present = [&v](int x)->bool{
      return  std::find(v.begin(),v.end(),x) != v.end();
  };      
  std::cout << (is_present(1)? "present" :" no present") <<std::endl;       
}

答案 4 :(得分:1)

如其他答案所述,将其移至函数。

如其他答案所述,您可以考虑根据需要添加constexpr / throw。

其他答案没有说,为此使用switch case语句;这样,您就可以用|| x ==替换所有case了-少了几个字符,这看起来似乎并不重要(实际上也不是);但最重要的是,消除了变量名称或|出错的可能性。

当您在该列表中有300个项目时,如果它不能正常工作,请相信我,您将很高兴不必检查每个||。是正确的。