winbgim studio programacion móviles libreria interfaz hacer graficos grafica ejemplos dev desarrollo curso como circulo aplicaciones c++ method-chaining syntactic-sugar function-calls member-functions

studio - libreria graphics.h en c++



¿Hay una manera de llamar a múltiples funciones en el mismo objeto con una línea? (6)

Esto puede no ser precisamente lo que estaba buscando pero no lo olvide, C ++ no es un lenguaje basado en líneas (bueno excepto por // comentarios).

Por lo tanto, es perfectamente razonable colocar varias declaraciones cortas y simples en una sola línea. Así para lograr:

llamar a una función miembro en una cola varias veces en la misma línea.

Usted necesita simplemente cambiar:

queue<int> q; q.push(0); q.push(1);

Dentro:

queue<int> q; q.push(0); q.push(1);

No, no elimina la escritura q dos veces, pero si ese es un problema, sospecho que es más probable que su problema sean variables con nombres excesivamente largos. Suponiendo que ese sea el caso, siempre recuerde que puede usar referencias para asignar identificadores locales más simples a una variable:

auto &foo = a_really_long_name_for_a_queue; foo.push(0); foo.push(1);

Solo intentaba ordenar un programa y me preguntaba si alguien podría darme un poco de sintaxis con respecto a llamar a una función miembro en una cola varias veces en la misma línea.

Por ejemplo, cambiando:

queue<int> q; q.push(0); q.push(1);

a algo como:

q.(push(0), push(1)); //or q.push(0).push(1);

Sé que parece un poco ridículo, y no es práctico. Pero si quisiera acortar una pequeña porción de código como esa, ¿hay alguna opción para hacerlo? Por lo que he leído hasta ahora, solo es posible encadenar métodos cuando la función tiene un void retorno no void .

Por supuesto, esta es una opción:

q.push(0); q.push(1);

Pero estoy tratando de evitar tener q allí dos veces. De nuevo ... azúcar sintáctica :)

El objetivo aquí no es inicializar, sino condensar el número de veces que un objeto / contenedor se activa en un bloque de código. La razón por la que estoy haciendo referencia a una cola es porque es dinámica.


Si no puedes modificar la clase, puedes usar el operador de coma:

#include<queue> #include<iostream> int main() { std::queue<int> q; (q.push(0), q).push(1); std::cout << q.size() << std::endl; }


Si tiene una clase que puede modificar, haga que la función devuelva una referencia a sí misma:

template<typename T> class queue { public: //... queue& push(T data) { //... return *this; //return current instance } //... private: //... };

Entonces puedes hacer

queue<int> q; q.push(0).push(1);

Si no puedes, entonces tus manos están atadas. Podría hacer una envoltura alrededor de la clase, pero para salvar algunos caracteres, esto no vale la pena.

En tu caso con push , puedes hacer:

queue<int> q = { 0, 1 };

Pero esto obviamente solo funciona con push , ya que la cola contendrá 0 y 1 después de los 2 push.


Siempre se puede definir una envoltura, como

template< class Item > void push( queue<Item>& q, std::initializer_list<Item> const& values ) { for( Item const& v : values ) { q.push( v ); } }

Entonces llámalo así:

push( q, {1, 2, 3} );

Si lo que desea no es conveniencia de notación, sino simplemente utilizar la técnica de interfaz fluida, si no puede modificar la clase, defina un operador:

template< class Item > auto operator<<( queue<Item>& q, Item v ) -> queue<Item>& { q.push( move( v ) ); return q; }

Entonces llámalo así:

q << 1 << 2 << 3;

Asegúrese de grabar a su colega tratando de familiarizarse con el código. :)

Oh, está bien, aún así, si no puedes modificar la clase, por supuesto puedes hacer esto:

template< class Item > struct Fluent { queue<Item>& items; auto push( Item v ) -> Fluent& { items.push( move( v ) ); return *this; } Fluent( queue<Item>& q ): items( q ) {} };

Entonces llámalo así:

Fluent( q ).push( 1 ).push( 2 ).push( 3 );

Descargo de responsabilidad: ninguno de los códigos tocados por el compilador.

¡Que te diviertas!


Solo por diversión, aquí hay un pequeño truco de plantilla que proporciona una forma de encadenar casi todos los métodos, ignorando los valores de retorno:

// The struct providing operator()(...) so that a call is simply // chainer_t_instance(param_for_call1)(param_for_call2)(param_for_call3); template <typename Class, typename Method> struct chainer_t { chainer_t(Class& instance, Method&& method) : _instance(instance), _method(method) {} chainer_t(chainer_t&& chainer) : _instance(chainer._instance), _method(chainer._method) {} // Avoid copy to avoid misunderstanding chainer_t(const chainer_t&) = delete; chainer_t& operator=(const chainer_t&) = delete; // Operator () takes anything template <typename... Types> chainer_t& operator()(Types&&... types) { (_instance.*_method)(std::forward<Types>(types)...); return *this; } protected: Class& _instance; Method& _method; }; // Just to ease the writting template <typename Class, typename Method> chainer_t<Class, Method> chain(Class& instance, Method&& method) { using chainer = chainer_t<Class, Method>; return chainer(instance, std::forward<Method>(method)); }

Una llamada encadenada será:

chain(my_instance, &my_class::add)(1)(2)(3)(4);

Ejemplo vivo


auto repeat_call = [](auto&& f){ return y_combinate( [f=decltype(f)(f)](auto&& self, auto&&...args)->decltype(self){ f( decltype(args)(args)... ); return decltype(self)(self); } ); };

Con y_combinate siendo ay combinator.

Ahora podemos repeat_call( [&](int x){ q.push(x); } )(1)(0);