Output a signature of a lambda call or an arbitrary call for make_function

In some situations, it is desirable to be able to erase the called one (for example, a function, function pointer, an object instance with operator() , lambda, mem_fn ), for example, in Using Boost adapters with C ++ 11 lambdas , which require a copyable and standard default type of.

std::function would be ideal, but there seems to be no way to automatically determine which signature creates an instance of std::function with. Is there an easy way to get the signature of an arbitrary called function and / or wrap it in the corresponding instance of std::function (i.e. make_function function make_function )?

In particular, I am looking for one or another of

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

so make_function([](int i) { return 0; }) returns a std::function<int(int)> . Obviously, this would not have to work if an instance could be called by more than one signature (for example, objects with more than one, template, or default operator() s parameter).

Boost is excellent, although non-Boost solutions that are not overly complex are preferred.




Edit: answering my own question.

+24
c ++ function lambda c ++ 11 type-inference
Aug 09 2018-12-12T00:
source share
3 answers

I came up with a rather nasty non-library solution using the fact that lambdas have 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)); } 

Any ideas where this can be simplified or improved? Any obvious errors?

+26
Sep 05
source share

impossible. You can take the address of operator() for some types, but not for an arbitrary caller, because it can have overloads or template parameters. Regardless of whether this will work for lambda, it is certainly not defined, AFAIK.

+2
Aug 09 2018-12-12T00:
source share

For non-invariant non-basic illiterate lambda functions, as well as simple free functions, you can use the following approach:

 #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; } 
0
Oct 21 '15 at 20:21
source share



All Articles