Reputation: 127
Is there any function which can help me do the following much more easily?
char ch = '+';
if (( ch == '+') || (ch == '-') || (ch == '*'))
{
//do something
}
Since have to check this several times in my code, I would prefer if there was any to do it similar to
char arr ={'+','-','*'};
if (ch in arr)
{
//do something
}
Upvotes: 1
Views: 965
Reputation: 83577
For this specific case, you can wrap the boolean expression in your own custom function:
bool isOperator(char ch) {
return ( ch == '+') || (ch == '-') || (ch == '*');
}
This will reduce the redundancy in the rest of your code since now you can just do
if(isOperator(ch))
Upvotes: 0
Reputation: 307
try this
#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;
}
Upvotes: 1
Reputation: 39390
For me, at first glance, this is a set lookup: is this element any of those is equivalent to does this set of elements contain this one. And, as such:
if ((std::set<char> {'a','b','c'}).count(x) > 0) {
// ...
}
Upvotes: 0
Reputation: 21160
This makes any
a compile time construct if your array is too. I can't really think of a way to make this more optimized if the range is arbitrary.
I've chosen to overload ==
because it looks nicer than passing the arguments side by side.
#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;
}
This results in a nice looking format
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;
is to alias the type Iter
dereferences to as value_type
.
template<typename T, size_t N>
any(T (&)[N]) -> any<T*>;
is to deduct the type of any
without explicit template parameters.
return it != end && (v == *it || compare(v, it + 1));
is to recursively check if the range has been exhausted and if not, check if the value is equal to the current element.
Note that any("+-*")
has 4 characters in it, the last one being '\0'
.
Upvotes: 0
Reputation: 93384
You can write a function that generates code equivalent to
if (( ch == '+') || (ch == '-') || (ch == '*'))
with a better user syntax.
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...);
}
Usage:
if(any(ch, '+', '-', '*')) { /* do something */ }
As shown by this godbolt.org comparison, this is an example of a zero-cost abstraction.
In C++17 you could use a fold expression:
template <typename X, typename... Ts>
bool any(const X& x, const Ts&... rest)
{
return ((x == rest) || ...);
}
If you want to reuse the same comparison values multiple times without repeating yourself, you can create a "curried" version of any
that first binds the arguments to check against and then does the comparison on a subsequent call.
template <typename... Ts>
auto bound_any(const Ts&... xs)
{
return [xs...](const auto& x)
{
return ((x == xs) || ...);
};
}
Usage:
auto is_op = bound_any('+', '-', '*');
if(is_op(ch)) { /* do something */ }
Here's a godbolt.org comparison.
Upvotes: 3
Reputation: 141648
In this case you can use:
if ( std::strchr("+-*", ch) )
The strchr
function, from #include <cstring>
, returns a null pointer iff the character is not found in the string.
Upvotes: 4