我需要为 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);
编译器资源管理器演示位于这里。
您可以重新修改此解决方案以删除 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*>
,因为这会导致悬空,所以库拒绝它。