So you want a radical change in language . In particular, you want to create your own operator. Are you ready?
Syntax
I want to change the syntax to use a list in the style of C and C ++:
if (x in {x0, ...}) ...
In addition, we will add our new operator in to any container for which begin() and end() are defined:
if (x in my_vector) ...
There is one caveat: this is not a true statement, so it should always be enclosed in brackets as its own expression:
bool ok = (x in my_array); my_function( (x in some_sequence) );
The code
The first thing to know is that RLM often requires the abuse of macros and operators. Fortunately, for a simple predicate for members, abuse is actually not so bad.
#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
Using
Fine! Now we can use it in every possible way so that you can use the operator in . In accordance with your particular interest, see Example 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"; }
Potential improvements
There are always things you can do to improve the code for your specific goals. You can add the ni (not-in) operator (add a new thunk container type). You can wrap thunk containers in a namespace (good idea). You can specialize in things like std::set to use the .count() member function instead of looking for O (n). Etc.
Other problems
const vs mutable : not a problem; both can be used with an operator- laziness
or : Technically, or not lazy, it is shorted. The std::find() algorithm also closes the same way. - reversal of the compilation cycle: not applicable here. No loops were used in the source code; while
std::find() does, any loop unfolding that might happen depends on the compiler. - it’s easy to extend to operators other than
== : this is really a separate issue; You no longer look at a simple membership predicate, but now consider a functional reset filter. It is possible to create an algorithm that does this, but the standard library provides any_of() , which does just that. (It's just not as pretty as our RLM “in” statement. However, any C ++ programmer will easily understand this. Such answers have already been proposed here.)
Hope this helps.