De hecho, escribí una pequeña utilidad que crea un funtor de invocación diferida (algo así como std::bind
-like, pero sin las funciones anidadas de bind/expressions placeholders).Mi motivación principal era este caso que encontré contrario a la intuición:
using pointer_type = std::unique_ptr<int>;
pointer_type source();
void sink(pointer_type p);
pointer_type p = source();
// Either not valid now or later when calling bound()
// auto bound = std::bind(sink, std::move(p));
auto bound = std::bind(
[](pointer_type& p) { sink(std::move(p)); }
, std::move(p));
bound();
La razón de que el adaptador (que se mueve a su argumento ref lvalue a sink
) es que el retorno de la llamada envoltura por std::bind
siempre envía los argumentos ligados como lvalues . Esto no fue un problema con, por ejemplo, boost::bind
en C++ 03 dado que lvalue se vincularía a un argumento de referencia del objeto invocable subyacente o a un argumento de valor a través de una copia. No funciona aquí ya que pointer_type
es de solo movimiento.
La idea de que lo que tengo es que en realidad hay dos cosas a considerar: cómo los argumentos con destino deben ser almacenados , y cómo deben ser restaurados (es decir, pasa al objeto invocable). El control que le otorga std::bind
es el siguiente: los argumentos se almacenan en un fondo (mediante el uso de std::ref
) o de manera regular (usando std::decay
con avance perfecto); siempre se restauran como valores l (con cv-qualifiers heredados del contenedor de llamadas propietarias). Excepto que puede eludir el último con una pequeña expresión lambda en el sitio como lo acabo de hacer.
Podría decirse que hay mucho control y mucha expresión para aprender relativamente poco. En comparación, mi utilidad tiene semántica como bind(f, p)
(copia de decaimiento y almacenamiento, restaurar como lvalue), bind(f, ref(p))
(almacenar superficialmente, restaurar como lvalue), bind(f, std::move(p))
(descomposición y almacenar desde mover, restaurar como valor r), bind(f, emplace(p))
(descomposición y almacenamiento desde movimiento, restaurar como lvalue). Esto se siente como aprender un EDSL.
Si enlaza una referencia a un local, tendrá problemas. – mfontanini
No lo seré si la función llamada no existe más allá del alcance del local. Hay muchas cosas en C++ que le permiten volar el pie. Mi pregunta es más al punto que este comportamiento parece ser menos intuitivo. – ryaner
En algún momento mi respuesta contenía un "y ese local queda fuera de alcance", pero aparentemente se borró después de la edición: S – mfontanini