假设我想写这样的东西(该{1, 3, 7, 42, 69, 550123}
集在编译之前就已知):
int x;
...
if (x == 1 || x == 3 || x == 7 || x == 42 || x == 69 || x == 5550123)
{
...
}
Run Code Online (Sandbox Code Playgroud)
这个条件看起来很难看,因为我们|| x ==
为每个可能的值都有9个额外的符号(" ").如何以更加C++的方式重写它?
我最好的猜测是:
int x;
...
const std::unordered_set<int> v = {1, 3, 7, 42, 69, 5550123};
if (v.count(x))
{
...
}
Run Code Online (Sandbox Code Playgroud)
它具有O(1)平均复杂度,有一些内存和时间开销,但看起来仍然有点难看.
编辑:我刚注意到c ++ 14标签.请注意,我的实现in
依赖于C++ 17.它也可以在C++ 14中使用递归来完成,但这涉及更多的样板,并且编译速度稍慢.
可以使用模板生成具有逻辑运算符序列的函数,例如nvoigt的答案中的函数:
template<auto... ts, class T>
constexpr bool
in(const T& t) noexcept(noexcept(((t == ts) || ...))) {
return ((t == ts) || ...);
}
// usage
if (in<1, 3, 7, 42, 69, 5550123>(x))
Run Code Online (Sandbox Code Playgroud)
也就是说,将一组魔术数隐藏在命名函数后面可能很有意义:
constexpr bool
is_magical(int x) noexcept {
return in<1, 3, 7, 42, 69, 5550123>(x);
}
Run Code Online (Sandbox Code Playgroud)
唯一干净的方法是将其移动到一个方法.适当地命名方法,你在里面做什么并不重要.
bool is_valid_foo_number(int x)
{
return x == 1
|| x == 3
|| x == 7
|| x == 42
|| x == 69
|| x == 5550123;
}
Run Code Online (Sandbox Code Playgroud)
这个方法对我来说足够好,因为我将会看到它
if (is_valid_foo_number(input))
{
// ...
}
Run Code Online (Sandbox Code Playgroud)
如果技术细节发生变化(例如需要另一种查找方法或可能是数据库而非硬编码值的大量有效数字),您可以更改方法的内部结构.
关键是我觉得它看起来很丑陋...因为你需要在看你的逻辑时看一下它.你不应该看看细节.