Tropezando con esta pregunta, me gustaría señalar a cualquiera que se encuentre con esto hoy en día que esto es posible con una sintaxis relativamente elegante utilizando solo la biblioteca estándar y algunas clases de ayuda gracias a decltype, auto y perfecto reenvío.
la definición de estas dos clases:
template <class Arg, class ArgCall, class OuterCall>
class pipe {
private:
ArgCall argcall;
OuterCall outercall;
public:
typedef pipe<Arg, ArgCall, OuterCall> this_type;
pipe(ArgCall ac, OuterCall oc) : argcall(ac), outercall(oc) {}
auto operator()(Arg arg) -> decltype(outercall(argcall(arg))) {
return outercall(argcall(arg));
}
template <class NewCall>
pipe<Arg, this_type, NewCall> operator[](NewCall&& nc) {
return {*this, std::forward<NewCall>(nc)};
}
};
template <class Arg>
class pipe_source {
public:
typedef pipe_source<Arg> this_type;
Arg operator()(Arg arg) {
return arg;
}
template <class ArgCall, class OuterCall>
static pipe<Arg, ArgCall, OuterCall> create(ArgCall&& ac, OuterCall&& oc) {
return {std::forward<ArgCall>(ac), std::forward<OuterCall>(oc)};
}
template <class OuterCall>
pipe<Arg, this_type, OuterCall> operator[](OuterCall&& oc) {
return {*this, std::forward<OuterCall>(oc)};
}
};
Un programa sencillo:
int f(int x) {
return x*x;
}
int g(int x) {
return x-2;
}
int h(int x) {
return x/2;
}
int main() {
auto foo = pipe_source<int>::create(f, g);
//or:
auto bar = pipe_source<int>()[g][h];
std::cout << foo(10) << std::endl;
std::cout << bar(10) << std::endl;
return 0;
}
Esto tiene la ventaja añadida de que una vez que está en una tubería, siempre que el tipo de retorno es correcta puede agregar otra función f a la cadena con tubería [f].
continuación:
$ g++ test.cpp -o test -std=c++11
$ ./test
98
4
$
puede usar 'impulsar :: bind' en lugar de' boost :: lambda :: bind' para esta tarea. Se ve como 'bind (g, bind (f, _1))'. ¿Sabes de eso? –
Sí, puede usar llamadas anidadas a 'boost :: bind' para crear funtores compuestos. Sin embargo, me preguntaba si había alguna forma mejor de hacerlo. – Channel72