examples c++ function lambda c++11 type-inference

c++ - examples - Inferir la firma de llamada de una lambda o arbitraria invocable para "make_function"



lambda examples c++ (3)

En algunas situaciones es deseable poder escribir y borrar un llamable (por ejemplo, función, puntero de función, instancia de objeto con operator() , lambda, mem_fn ), por ejemplo, en el uso de adaptadores Boost con C ++ 11 lambdas donde una copia asignable y se requiere un tipo construible por defecto.

std::function sería ideal, pero parece que no hay manera de determinar automáticamente con qué firmas crear una instancia de la plantilla de clase std::function . ¿Hay una manera fácil de obtener la firma de la función de un invocable arbitrario y / o envolverlo en una instancia de instanciación std::function apropiada (es decir, una plantilla de función make_function )?

Específicamente, estoy buscando uno u otro de

template<typename F> using get_signature = ...; template<typename F> std::function<get_signature<F>> make_function(F &&f) { ... }

tal que make_function([](int i) { return 0; }) devuelve una std::function<int(int)> . Obviamente, no se esperaría que esto funcione si una instancia es invocable con más de una firma (por ejemplo, objetos con más de una, plantilla o operator() parámetros por defecto operator() s).

Boost está bien, aunque se prefieren las soluciones que no son Boost que no son excesivamente complejas.

Editar: respondiendo mi propia pregunta.


He encontrado una solución bastante desagradable que no es de biblioteca, usando el hecho de que lambdas tiene operator() :

template<typename T> struct remove_class { }; template<typename C, typename R, typename... A> struct remove_class<R(C::*)(A...)> { using type = R(A...); }; template<typename C, typename R, typename... A> struct remove_class<R(C::*)(A...) const> { using type = R(A...); }; template<typename C, typename R, typename... A> struct remove_class<R(C::*)(A...) volatile> { using type = R(A...); }; template<typename C, typename R, typename... A> struct remove_class<R(C::*)(A...) const volatile> { using type = R(A...); }; template<typename T> struct get_signature_impl { using type = typename remove_class< decltype(&std::remove_reference<T>::type::operator())>::type; }; template<typename R, typename... A> struct get_signature_impl<R(A...)> { using type = R(A...); }; template<typename R, typename... A> struct get_signature_impl<R(&)(A...)> { using type = R(A...); }; template<typename R, typename... A> struct get_signature_impl<R(*)(A...)> { using type = R(A...); }; template<typename T> using get_signature = typename get_signature_impl<T>::type; template<typename F> using make_function_type = std::function<get_signature<F>>; template<typename F> make_function_type<F> make_function(F &&f) { return make_function_type<F>(std::forward<F>(f)); }

¿Alguna idea donde esto puede ser simplificado o mejorado? ¿Algún error obvio?


Imposible. Es posible que pueda tomar la dirección del operator() para algunos tipos, pero no para un llamador arbitrario, porque puede tener sobrecargas o parámetros de plantilla. Ya sea que funcione o no para una lambda seguramente no está bien definido, AFAIK.


Para las funciones lambda sin captura no genéricas no variadas, así como las funciones libres simples, se puede usar el siguiente enfoque:

#include <iostream> #include <cstdlib> template< typename L, typename R, typename ...A > constexpr auto // std::function< R (A...) > to_function_pointer(L l, R (L::*)(A...) const) { return static_cast< R (*)(A...) >(l); } template< typename L, typename R, typename ...A > constexpr auto // std::function< R (A...) > to_function_pointer(L l, R (L::*)(A...)) // for mutable lambda { return static_cast< R (*)(A...) >(l); } template< typename L > constexpr auto to_function_pointer(L l) { return to_function_pointer(l, &L::operator ()); } template< typename R, typename ...A > constexpr auto // std::function< R (A...) > to_function_pointer(R (* fp)(A...)) { return fp; } namespace { void f() { std::cout << __PRETTY_FUNCTION__ << std::endl; } } int main() { to_function_pointer([] () { std::cout << __PRETTY_FUNCTION__ << std::endl; })(); //to_function_pointer([&] () { std::cout << __PRETTY_FUNCTION__ << std::endl; })(); // can''t cast from non-captureless lambda to function pointer to_function_pointer([] () mutable { std::cout << __PRETTY_FUNCTION__ << std::endl; })(); to_function_pointer(f)(); to_function_pointer(&f)(); return EXIT_SUCCESS; }