I need to create a wrapper for lambda function that would take a tuple of parameters of the original lambda function and use its implementation. I'm using C++23 compiler. This is the function I came up with:
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)); };
}
To make it work I need to create a lambda_traits
class the instantiation of which on lambda type deduces the Args
type, which is a tuple of lambda parameters. For example, for lambda function [](int i, int j){}
the Args
would be tuple<int, int>
.
After experimenting with possible solutions to lambda_traits
I finally cheated and delegated the type deduction to 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
looks like a kludge here, I tried to replace it but couldn't find the way to make it work. Can you rework this solution removing std::function
?
Another problem, the implicit conversions are not happening in some cases, probably something is wrong with types somewhere. Can you fix that?
This works:
static_assert(
wrap([](std::string s) { return s.size();})(std::tuple{"abc"}) == 3);
This doesn't:
static_assert(
wrap([](const std::string& s) { return s.size();})(std::tuple{"abc"}) == 3);
Compiler explorer demo is here.
Can you rework this solution removing std::function?
You can reimplement the deduction guides for std::function
, which is not difficult
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())>
{
};
Another problem, the implicit conversions are not happening in some cases, probably something is wrong with types somewhere. Can you fix that?
Because you can't construct a tuple<const std::string&>
from a tuple<const char*>
which would result in a dangling reference, so the library rejects it.