29

在某些情况下,希望能够对可调用对象(例如函数、函数指针、带有operator()、lambda 的对象实例mem_fn)进行类型擦除,例如在Using Boost adapters with C++11 lambdas where a copy-assignable and default-constructible类型是必需的。

std::function将是理想的,但似乎没有办法自动确定用什么签名来实例化类模板std::function。是否有一种简单的方法来获取任意可调用的函数签名和/或将其包装在适当的std::function实例化实例(即make_function函数模板)中?

具体来说,我正在寻找一种或另一种

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

这样make_function([](int i) { return 0; })返回一个std::function<int(int)>. 显然,如果一个实例可以用多个签名调用(例如,具有多个签名的对象,模板或默认参数operator()),这将不会起作用。

Boost 很好,尽管不太复杂的非 Boost 解决方案是首选。


编辑:回答我自己的问题。

4

3 回答 3

30

我想出了一个相当讨厌的非库解决方案,使用 lambdas 的事实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)); }

有什么可以简化或改进的想法吗?有什么明显的bug吗?

于 2012-09-05T13:58:27.837 回答
2

不可能的。您可能能够operator()获取某些类型的地址,但不能获取任意可调用的地址,因为它很可能具有重载或模板参数。它是否适用于 lambda 肯定没有明确定义,AFAIK。

于 2012-08-09T23:06:50.113 回答
1

对于非可变非泛型无捕获 lambda 函数以及简单的自由函数,可以使用以下方法:

#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;
}
于 2015-10-21T20:21:31.870 回答