Alrighty, alors, vous voulez Radicale de la Langue de Modification. Plus précisément, vous voulez créer votre propre opérateur. Est-il prêt?
La syntaxe
Je vais modifier la syntaxe à utiliser un C et C++-style de liste:
if (x in {x0, ...}) ...
En outre, nous allons laisser nos nouvelles en exploitant s'appliquer à n'importe quel conteneur pour qui begin()
et end()
sont définies:
if (x in my_vector) ...
Il y a une mise en garde: ce n'est pas un vrai opérateur et donc il doit toujours être mis entre parenthèses car il est propre expression:
bool ok = (x in my_array);
my_function( (x in some_sequence) );
Le code
La première chose à prendre en compte est que RLM nécessite souvent une macro et l'opérateur de l'abus. Heureusement, pour une simple adhésion de prédicat, l'abus est en fait pas si mal que ça.
#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
L'utilisation de la
Super! Maintenant, nous pouvons l'utiliser dans toutes les manières que vous attendez une à l'opérateur d'être utile. Selon votre domaine d'intérêt particulier, voir exemple 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";
}
Améliorations possibles
Il y a toujours des choses qui peut être fait pour améliorer le code à vos besoins. Vous pouvez ajouter un ni (non -) opérateur (Ajouter un thunk de nouveau type de conteneur). Vous pouvez envelopper le thunk conteneurs dans un espace de noms (une bonne idée). Vous pouvez vous spécialiser sur des choses comme l' std::set
utilisation de l' .count()
fonction de membre au lieu de O(n) de recherche. Etc.
Vos autres préoccupations
-
const
vs mutable
: pas un problème; les deux sont utilisables avec l'opérateur
- la paresse de l'
or
: Techniquement, or
est pas paresseux, il est court-circuité. L' std::find()
algorithme également des courts-circuits, de la même façon.
- le temps de compilation déroulement de la boucle : pas vraiment applicable ici. Votre code d'origine n'a pas utiliser de boucles; tandis que,
std::find()
n', toute déroulement de la boucle qui peut se produire est le compilateur.
- facile d'étendre à d'autres opérateurs que
==
: C'est effectivement une question distincte, vous n'êtes plus à la recherche à une simple adhésion de prédicat, mais sont en train d'examiner une fonctionnelle fois-filtre. Il est tout à fait possible de créer un algorithme qui le fait, mais la Bibliothèque Standard fournit l' any_of()
de la fonction, ce qui est exactement ce que fait. (C'est juste pas aussi jolie que notre RLM 'dans' l'opérateur. Cela dit, tout programmeur C++ de se comprendre facilement. Ces réponses ont déjà été proposées ici.)
Espérons que cette aide.