让我们说我要写这样的东西({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),有一些内存和时间开销,但看起来仍然很丑。
答案 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个项目时,如果它不能正常工作,请相信我,您将很高兴不必检查每个||。是正确的。