有没有更好的方法来编写这样的代码:
if (var == "first case" or var == "second case" or var == "third case" or ...)
Run Code Online (Sandbox Code Playgroud)
在Python中我可以写:
if var in ("first case", "second case", "third case", ...)
Run Code Online (Sandbox Code Playgroud)
这也让我有机会轻松通过好的选项列表:
good_values = "first case", "second case", "third case"
if var in good_values
Run Code Online (Sandbox Code Playgroud)
这只是一个例子:类型var可能与字符串不同,但我只对alternative(or)比较(==)感兴趣.var可以是非const,而选项列表在编译时是已知的.
专享奖金:
or==Sla*_*ava 44
如果你想扩展它的编译时间你可以使用这样的东西
template<class T1, class T2>
bool isin(T1&& t1, T2&& t2) {
return t1 == t2;
}
template<class T1, class T2, class... Ts>
bool isin(T1&& t1 , T2&& t2, T2&&... ts) {
return t1 == t2 || isin(t1, ts...);
}
std::string my_var = ...; // somewhere in the code
...
bool b = isin(my_var, "fun", "gun", "hun");
Run Code Online (Sandbox Code Playgroud)
我实际上没有测试它,这个想法来自Alexandrescu的'Variadic模板是funadic'谈话.因此,对于细节(和正确实施)观看.
编辑:在c ++ 17中,他们引入了一个很好的折叠表达式语法
template<typename... Args>
bool all(Args... args) { return (... && args); }
bool b = all(true, true, true, false);
// within all(), the unary left fold expands as
// return ((true && true) && true) && false;
// b is false
Run Code Online (Sandbox Code Playgroud)
Ker*_* SB 27
该any_of算法在这里可以很好地工作:
#include <algorithm>
#include <initializer_list>
auto tokens = { "abc", "def", "ghi" };
bool b = std::any_of(tokens.begin(), tokens.end(),
[&var](const char * s) { return s == var; });
Run Code Online (Sandbox Code Playgroud)
(您可能希望将范围限制tokens在最小的必需上下文中.)
或者您创建一个包装器模板:
#include <algorithm>
#include <initializer_list>
#include <utility>
template <typename T, typename F>
bool any_of_c(const std::initializer_list<T> & il, F && f)
{
return std::any_of(il.begin(), il.end(), std::forward<F>(f));
}
Run Code Online (Sandbox Code Playgroud)
用法:
bool b = any_of_c({"abc", "def", "ghi"},
[&var](const char * s) { return s == var; });
Run Code Online (Sandbox Code Playgroud)
Dút*_*has 11
好吧,那么,你想要激进的语言修改.具体来说,您想要创建自己的运算符.准备?
句法
我将修改语法以使用C和C++样式列表:
if (x in {x0, ...}) ...
Run Code Online (Sandbox Code Playgroud)
此外,我们将让我们的新的运营商适用于针对任何容器begin()和end()定义如下:
if (x in my_vector) ...
Run Code Online (Sandbox Code Playgroud)
有一点需要注意:它不是一个真正的运算符,所以它必须始终用括号表示它自己的表达式:
bool ok = (x in my_array);
my_function( (x in some_sequence) );
Run Code Online (Sandbox Code Playgroud)
代码
首先要注意的是,RLM通常需要一些宏观和操作员滥用.幸运的是,对于一个简单的成员谓词,滥用实际上并没有那么糟糕.
#ifndef DUTHOMHAS_IN_OPERATOR_HPP
#define DUTHOMHAS_IN_OPERATOR_HPP
#include <algorithm>
#include <initializer_list>
#include <iterator>
#include <type_traits>
#include <vector>
//----------------------------------------------------------------------------
// The 'in' operator is magically defined to operate on any container you give it
#define in , in_container() =
//----------------------------------------------------------------------------
// The reverse-argument membership predicate is defined as the lowest-precedence
// operator available. And conveniently, it will not likely collide with anything.
template <typename T, typename Container>
typename std::enable_if <!std::is_same <Container, T> ::value, bool> ::type
operator , ( const T& x, const Container& xs )
{
using std::begin;
using std::end;
return std::find( begin(xs), end(xs), x ) != end(xs);
}
template <typename T, typename Container>
typename std::enable_if <std::is_same <Container, T> ::value, bool> ::type
operator , ( const T& x, const Container& y )
{
return x == y;
}
//----------------------------------------------------------------------------
// This thunk is used to accept any type of container without need for
// special syntax when used.
struct in_container
{
template <typename Container>
const Container& operator = ( const Container& container )
{
return container;
}
template <typename T>
std::vector <T> operator = ( std::initializer_list <T> xs )
{
return std::vector <T> ( xs );
}
};
#endif
Run Code Online (Sandbox Code Playgroud)
用法
大!现在,我们可以用它所有你所期望的方式在运营商是有用的.根据您的特殊兴趣,请参见示例3:
#include <iostream>
#include <set>
#include <string>
using namespace std;
void f( const string& s, const vector <string> & ss ) { cout << "nope\n\n"; }
void f( bool b ) { cout << "fooey!\n\n"; }
int main()
{
cout <<
"I understand three primes by digit or by name.\n"
"Type \"q\" to \"quit\".\n\n";
while (true)
{
string s;
cout << "s? ";
getline( cin, s );
// Example 1: arrays
const char* quits[] = { "quit", "q" };
if (s in quits)
break;
// Example 2: vectors
vector <string> digits { "2", "3", "5" };
if (s in digits)
{
cout << "a prime digit\n\n";
continue;
}
// Example 3: literals
if (s in {"two", "three", "five"})
{
cout << "a prime name!\n\n";
continue;
}
// Example 4: sets
set <const char*> favorites{ "7", "seven" };
if (s in favorites)
{
cout << "a favorite prime!\n\n";
continue;
}
// Example 5: sets, part deux
if (s in set <string> { "TWO", "THREE", "FIVE", "SEVEN" })
{
cout << "(ouch! don't shout!)\n\n";
continue;
}
// Example 6: operator weirdness
if (s[0] in string("014") + "689")
{
cout << "not prime\n\n";
continue;
}
// Example 7: argument lists unaffected
f( s, digits );
}
cout << "bye\n";
}
Run Code Online (Sandbox Code Playgroud)
潜在的改进
总有一些事情可以用来改进特定目的的代码.您可以添加ni(not-in)运算符(添加新的thunk容器类型).您可以将thunk容器包装在命名空间中(这是一个好主意).您可以专注于std::set使用.count()成员函数而不是O(n)搜索.等等.
你的其他问题
constvs mutable:不是问题; 两者都可以与操作员一起使用or:从技术上讲,or是不是偷懒,这是短路.该std::find()算法也以相同的方式短路.std::find(),任何可能发生的循环都取决于编译器.==:这实际上是一个单独的问题; 你不再看一个简单的成员谓词,但现在正在考虑一个功能性的折叠过滤器.完全有可能创建一个算法,但标准库提供了这样的any_of()功能.(它不像我们的RLM''运算符那么漂亮.也就是说,任何C++程序员都会很容易理解它.这里已经提供了这样的答案.)希望这可以帮助.
首先,我建议使用
for循环,这是最简单和最易读的解决方案:Run Code Online (Sandbox Code Playgroud)for (i = 0; i < n; i++) { if (var == eq[i]) { // if true break; } }
然而,其他一些方法也可以,例如std::all_of,std::any_of,std::none_of(在#include <algorithm>).
让我们看一下包含所有上述关键字的简单示例程序
#include <vector>
#include <numeric>
#include <algorithm>
#include <iterator>
#include <iostream>
#include <functional>
int main()
{
std::vector<int> v(10, 2);
std::partial_sum(v.cbegin(), v.cend(), v.begin());
std::cout << "Among the numbers: ";
std::copy(v.cbegin(), v.cend(), std::ostream_iterator<int>(std::cout, " "));
std::cout << '\\n';
if (std::all_of(v.cbegin(), v.cend(), [](int i){ return i % 2 == 0; }))
{
std::cout << "All numbers are even\\n";
}
if (std::none_of(v.cbegin(), v.cend(), std::bind(std::modulus<int>(),
std::placeholders::_1, 2)))
{
std::cout << "None of them are odd\\n";
}
struct DivisibleBy
{
const int d;
DivisibleBy(int n) : d(n) {}
bool operator()(int n) const { return n % d == 0; }
};
if (std::any_of(v.cbegin(), v.cend(), DivisibleBy(7)))
{
std::cout << "At least one number is divisible by 7\\n";
}
}
Run Code Online (Sandbox Code Playgroud)
您可以使用std :: set来测试var是否属于它.(在启用c ++ 11的情况下编译)
#include <iostream>
#include <set>
int main()
{
std::string el = "abc";
if (std::set<std::string>({"abc", "def", "ghi"}).count(el))
std::cout << "abc belongs to {\"abc\", \"def\", \"ghi\"}" << std::endl;
return 0;
}
Run Code Online (Sandbox Code Playgroud)
优点是与非紧凑型女巫相比std::set<std::string>::count,O(log(n))及时工作(其中是n要测试的弦的数量).缺点是该组的构造需要.所以,构建一次,如:ifO(n)O(n*log(n))
static std::set<std::string> the_set = {"abc", "def", "ghi"};
Run Code Online (Sandbox Code Playgroud)
但是,IMO最好保持条件不变,除非它包含超过10个字符串来检查.使用std :: set进行此类测试的性能优势仅适用于大型n.此外,if对于普通的c ++开发人员来说,简单的非紧凑更容易阅读.
最接近的是:
template <class K, class U, class = decltype(std::declval<K>() == std::declval<U>())>
bool in(K&& key, std::initializer_list<U> vals)
{
return std::find(vals.begin(), vals.end(), key) != vals.end();
}
Run Code Online (Sandbox Code Playgroud)
我们需要采取类型的参数initializer_list<U>,这样我们就可以在通过支撑-初始化列表一样{a,b,c}.这复制了元素,但可能我们要这样做,因为我们提供文字所以可能没什么大不了的.
我们可以这样使用:
std::string var = "hi";
bool b = in(var, {"abc", "def", "ghi", "hi"});
std::cout << b << std::endl; // true
Run Code Online (Sandbox Code Playgroud)