write truncas son simple que pasado oraciones haber futuro español con c++ if-statement

c++ - simple - que son oraciones truncas



Forma compacta de escribir una declaración if(..) con muchas igualdades (9)

Primero, recomiendo usar un bucle for , que es la solución más fácil y fácil de leer:

for (i = 0; i < n; i++) { if (var == eq[i]) { // if true break; } }

Sin embargo, algunos otros métodos también están disponibles, por ejemplo, std::all_of , std::any_of , std::none_of (en #include <algorithm> ).

Veamos el sencillo programa de ejemplo que contiene todas las palabras clave anteriores.

#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"; } }

¿Hay una mejor manera de escribir código como este:

if (var == "first case" or var == "second case" or var == "third case" or ...)

En Python puedo escribir:

if var in ("first case", "second case", "third case", ...)

lo que también me da la oportunidad de pasar fácilmente la lista de buenas opciones:

good_values = "first case", "second case", "third case" if var in good_values

Esto es solo un ejemplo: el tipo de var puede ser diferente de una cadena, pero solo estoy interesado en comparaciones alternativas ( or ) ( == ). var puede ser no const , mientras que la lista de opciones se conoce en tiempo de compilación.

Bonificación profesional:

  • pereza or
  • tiempo de compilación desenrollado de bucle
  • fácil de extender a otros operadores que ==

El algoritmo any_of podría funcionar razonablemente bien aquí:

#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; });

(Es posible que desee limitar el alcance de los tokens al contexto mínimo requerido).

O crea una plantilla de contenedor:

#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)); }

Uso:

bool b = any_of_c({"abc", "def", "ghi"}, [&var](const char * s) { return s == var; });


Lo más parecido sería algo como:

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(); }

Necesitamos tomar un argumento de tipo initializer_list<U> para que podamos pasar una lista de inicialización arriostrada como {a,b,c} . Esto copia los elementos, pero presumiblemente lo haremos porque estamos proporcionando literales, por lo que probablemente no sea un gran problema.

Podemos usar eso así:

std::string var = "hi"; bool b = in(var, {"abc", "def", "ghi", "hi"}); std::cout << b << std::endl; // true


Muy bien, entonces, quieres la modificación del lenguaje radical . Específicamente, desea crear su propio operador. Listo?

Sintaxis

Voy a modificar la sintaxis para usar una lista de estilo C y C ++:

if (x in {x0, ...}) ...

Además, dejaremos que nuestro nuevo operador in se aplique a cualquier contenedor para el que se definan begin() y end() :

if (x in my_vector) ...

Hay una advertencia: no es un operador verdadero y, por lo tanto, siempre debe estar entre paréntesis como su propia expresión:

bool ok = (x in my_array); my_function( (x in some_sequence) );

El código

Lo primero que debe tener en cuenta es que RLM a menudo requiere un poco de abuso de macro y operador. Afortunadamente, para un predicado de membresía simple, el abuso en realidad no es tan malo.

#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

Uso

¡Excelente! Ahora podemos usarlo de todas las formas en que esperaría que un operador in sea ​​útil. Según su interés particular, vea el ejemplo 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"; }

Posibles mejoras

Siempre hay cosas que se pueden hacer para mejorar el código para sus propósitos específicos. Puede agregar un operador ni (no incluido) (Agregar un nuevo tipo de contenedor thunk). Puede envolver los contenedores de enlaces en un espacio de nombres (una buena idea). Puede especializarse en cosas como std::set para usar la función miembro .count() lugar de la búsqueda O (n). Etc.

Sus otras preocupaciones

  • const vs mutable : no es un problema; ambos son utilizables con el operador
  • pereza or : Técnicamente, or no es perezoso, está en cortocircuito. El algoritmo std::find() también cortocircuita de la misma manera.
  • tiempo de compilación desenrollado de bucle: no es realmente aplicable aquí. Su código original no usó bucles; mientras que std::find() hace, cualquier desenrollamiento de bucle que pueda ocurrir depende del compilador.
  • fácil de extender a operadores que no sean == : Eso en realidad es un problema separado; ya no está mirando un predicado de membresía simple, sino que ahora está considerando un filtro plegable funcional. Es completamente posible crear un algoritmo que haga eso, pero la Biblioteca Estándar proporciona la función any_of() , que hace exactamente eso. (Simplemente no es tan bonito como nuestro operador RLM ''in''. Dicho esto, cualquier programador de C ++ lo entenderá fácilmente. Estas respuestas ya se han ofrecido aquí).

Espero que esto ayude.


Podrías usar una caja de interruptor. En lugar de tener una lista de casos separados, podría tener:

incluir

usando el espacio de nombres estándar;

int main () {char grade = ''B'';

switch(grade) { case ''A'' : case ''B'' : case ''C'' : cout << "Well done" << endl; break; case ''D'' : cout << "You passed" << endl; break; case ''F'' : cout << "Better try again" << endl; break; default : cout << "Invalid grade" << endl; } cout << "Your grade is " << grade << endl; return 0;

}

Para que pueda agrupar sus resultados: A, B y C generarán "bien hecho". Tomé este ejemplo de Tutorials Point: http://www.tutorialspoint.com/cplusplus/cpp_switch_statement.htm


Puede usar std :: set para probar si var le pertenece. (Compilar con c ++ 11 habilitado)

#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; }

La ventaja es que std::set<std::string>::count funciona en tiempo O(log(n)) (donde n es el número de cadenas para probar) en comparación con no compacto if bruja es O(n) en general. La desventaja es que la construcción del conjunto toma O(n*log(n)) . Entonces, construya una vez, como:

static std::set<std::string> the_set = {"abc", "def", "ghi"};

Pero, en mi opinión, sería mejor dejar la condición como está, a menos que contenga más de 10 cadenas para verificar. Las ventajas de rendimiento del uso de std :: set para tal prueba aparecen solo para n grande. Además, simple no compacto if es más fácil de leer para un desarrollador promedio de c ++.


Si tiene acceso a C ++ 14 (no estoy seguro si esto funciona con C ++ 11) podría escribir algo como esto:

template <typename T, typename L = std::initializer_list<T>> constexpr bool is_one_of(const T& value, const L& list) { return std::any_of(std::begin(list), std::end(list), [&value](const T& element) { return element == value; }); };

Una llamada se vería así:

std::string test_case = ...; if (is_one_of<std::string>(test_case, { "first case", "second case", "third case" })) {...}

o así

std::string test_case = ...; std::vector<std::string> allowedCases{ "first case", "second case", "third case" }; if (is_one_of<std::string>(test_case, allowedCases)) {...}

Si no desea "ajustar" los casos permitidos en un tipo de lista, también puede escribir una pequeña función auxiliar como esta:

template <typename T, typename...L> constexpr bool is_one_of(const T& value, const T& first, const L&... next) //First is used to be distinct { return is_one_of(value, std::initializer_list<T>{first, next...}); };

Esto le permitirá llamarlo así:

std::string test_case = ...; if (is_one_of<std::string>(test_case, "first case", "second case", "third case" )) {...}

Ejemplo completo sobre Coliru


Vale la pena señalar que en la mayoría de los códigos Java y C ++ que he visto, enumerar 3 o más condicionales es la práctica aceptada. Ciertamente es más legible que las soluciones "inteligentes". Si esto sucede con tanta frecuencia, es un gran obstáculo, de todos modos, es un olor a diseño y un enfoque con plantilla o polimórfico probablemente ayudaría a evitar esto.

Entonces mi respuesta es la operación "nula". Solo sigue haciendo lo más detallado, es lo más aceptado.


si quieres expandirlo en tiempo de compilación puedes usar algo como esto

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");

En realidad no lo probé, y la idea proviene de la charla de Alexandrescu ''Las plantillas variables son funódicas''. Entonces, para los detalles (y la implementación adecuada) mira eso.

Editar: en c ++ 17 introdujeron una buena sintaxis de expresión de pliegue

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