如何将 lambda 函数转换为另一个采用参数元组的函数

问题描述 投票:0回答:1

我需要为 lambda 函数创建一个包装器,它将采用原始 lambda 函数的参数元组并使用其实现。我正在使用 C++23 编译器。这是我想出的功能:

template<class Fn>
constexpr auto wrap(Fn fn) 
{ 
    return [fn](typename lambda_traits<Fn>::Args&& t) { return std::apply(fn, std::forward<decltype(t)>(t)); };
}

为了使其工作,我需要创建一个

lambda_traits
类,该类在 lambda 类型上的实例化推导出
Args
类型,它是 lambda 参数的元组。例如,对于 lambda 函数
[](int i, int j){}
Args
将是
tuple<int, int>

在尝试了

lambda_traits
的可能解决方案后,我最终作弊并将类型推导委托给了
std::function

template<class Fn> struct lambda_traits;

template< class R, class ... A >
struct lambda_traits<R(A...)>
{
    using Ret = R;
    using Args = std::tuple<A...>;

    constexpr lambda_traits(std::function<R(A...)>);
};

template< class R, class ... A >
lambda_traits(std::function<R(A...)>) -> lambda_traits<R(A...)>;

template<class Fn> 
struct lambda_traits : decltype(lambda_traits(std::function(std::declval<Fn>())))
{
};

std::function
这里看起来像是一个拼凑,我试图替换它,但找不到让它工作的方法。你能重新修改这个解决方案,删除
std::function
吗?

另一个问题,在某些情况下隐式转换不会发生,可能是某个地方的类型出了问题。你能解决这个问题吗?

这有效:

static_assert(
    wrap([](std::string s) { return s.size();})(std::tuple{"abc"}) == 3);

这不是:

static_assert(
    wrap([](const std::string& s) { return s.size();})(std::tuple{"abc"}) == 3);

编译器资源管理器演示位于这里

c++ lambda c++23 c++-templates
1个回答
0
投票

您可以重新修改此解决方案以删除 std::function 吗?

你可以重新实现

std::function
的推演指南,这并不难

template<class Fn> struct lambda_traits ;

template< class R, class G, class ... A >
struct lambda_traits<R(G::*)(A...) const>
{
    using Ret = R;
    using Args = std::tuple<A...>;
};

template<class Fn> 
struct lambda_traits : lambda_traits<decltype(&Fn::operator())>
{
};

演示

另一个问题,隐式转换在某些情况下没有发生 在这种情况下,可能是某个地方的类型出了问题。你能修好吗 那?

这只是因为你不能从

tuple<const std::String&>
构造
tuple<const int*>
,因为这会导致悬空,所以库拒绝它。

© www.soinside.com 2019 - 2024. All rights reserved.