gpt4 book ai didi

c++ - 不使用 std::function 将捕获的 lambda 转换为函数指针

转载 作者:行者123 更新时间:2023-11-30 03:46:34 30 4
gpt4 key购买 nike

考虑以下示例:

using function_pair = std::pair<int, void(*)(void*)>; // This line cannot change
template <class Arg, class F>
function_pair make_function_pair(int i, F&& f)
{
return function_pair(i,
[&](void* x){std::forward<F>(f)(static_cast<Arg*>(x));}); // Not working
}

// Later in code
auto p1 = make_function_pair<char>(1, [](char* x){std::cout<<*x<<std::endl;});
auto p2 = make_function_pair<double>(2, [](double* x){*x = *x*2;});
auto p3 = make_function_pair<float>(3, [](float* x){*x = *x*3;});

由于捕获 lambda,代码无法编译(当 lambda 不必捕获 f 时,它可以工作)。我想知道如何在不使用 std::function 的情况下完成这项工作,因为 std::function 的计算开销很大,我负担不起。即使没有这个实际原因,我想知道如何在不使用 std::function 的情况下解决这个“学术”问题。

最佳答案

hack 解决方案依赖于这样一个事实,即非捕获 lambda 不会在我见过的每个 C++ 实现中都使用它的状态。

template<class F>
struct stateless_t {
constexpr stateless_t() {
static_assert( std::is_empty<F>::value, "Only works with stateless lambdas" );
}
using F_ref = F const&;
template<class...Ts>
std::result_of_t<F_ref(Ts...)> operator()(Ts&&...ts)const {
return (*reinterpret_cast<F const*>(this))(std::forward<Ts>(ts)...);
}
};

template<class F>
stateless_t<F> stateless() { return {}; }

template <class Arg, class F>
function_pair make_function_pair(int i, F const&)
{
return function_pair(
i,
[](void* x){return stateless<F>()(static_cast<Arg*>(x));}
);
}

这是左右和居中的未定义行为,但可能适用于您的编译器。

更好的选择是使用 std::function 并在拒绝该选项之前测量开销。对于小型函数对象,std::function 的开销很小(虚拟调用而不是函数指针调用)。

接下来,编写您自己的 std::function 以减少开销或找到一个(比如尽可能快的委托(delegate))。例如,您可以制作一个更快的 std::function,将调用指针存储在类本身而不是 vtable 中。

或者,也是 UB,但比上面更好——将无状态 lambda 转换为 void(T*),然后将其重新解释为 void(void*)。虽然仍然是 UB,但大多数实现使用二进制兼容的指针大小,以及可以在两者之间转换的函数指针。 @Pradhan 在上面的评论中提出了这一点。

一般来说,避免使用 UB,因为它从那时起会增加持续的维护开销。您已经在当前的编译器中测试了它,但是您必须检查它在 每个编译器每个构建 中是否正常工作,从现在开始使用每个编译器设置直到代码生命周期结束,才能使其长期可靠。

关于c++ - 不使用 std::function 将捕获的 lambda 转换为函数指针,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34027312/

30 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com