[英]How to call function that use part of template parameter pack in c++?
I have following problem:我有以下问题:
I want to create variadic template class, that must call lambda, that may take first N parameters of template parameter pack (N may vary from 0 to the size of parameters pack and differs for different lambda).我想创建可变参数模板 class,它必须调用 lambda,它可能采用模板参数包的前 N 个参数(N 可能从 0 到参数包的大小不等,并且因不同的 lambda 而异)。
I think, that recursive template helper function, that will check if lambda is invokable, starting with all parameters, should be the best variant, but how can I pass all but last parameters from parameters pack to it and is it possible at all?我认为,递归模板助手 function 将检查 lambda 是否可调用,从所有参数开始,应该是最好的变体,但我如何将参数包中除最后一个参数之外的所有参数传递给它,这是否可能?
At the moment I see it as something like this:目前我认为它是这样的:
template< typename Callable, typename ...Args >
void Call( Callable& cb, Args... args )
{
using Function = std::remove_reference_t< Callable >;
if constexpr( std::is_invocable_v< Function, Args... > )
cb( args... );
else if constexpr( sizeof...( args ) == 0 )
cb();
else
{
// Here I want to create shortened_args, that are all args but last one.
// Call( cb, shortened_args... );
}
}
UPD: I didn't mention it first, but I need C++17 solution. UPD:我没有先提到它,但我需要 C++17 解决方案。
You might use std::index_sequence
as helper:您可以使用
std::index_sequence
作为助手:
template <typename Callable, typename Tuple, std::size_t... Is>
constexpr std::size_t is_invocable_args(std::index_sequence<Is...>)
{
return std::is_invocable_v<Callable, std::tuple_element_t<Is, Tuple>...>;
}
// Helper to know max number of args to take from tuple
template <typename Callable, typename Tuple, std::size_t... Is>
constexpr std::size_t max_invocable_args(std::index_sequence<Is...>)
{
std::array<bool, sizeof...(Is)> a = {
is_invocable_args<Callable, Tuple>(std::make_index_sequence<Is>{})...
};
auto rit = std::find(a.rbegin(), a.rend(), true);
if (rit == a.rend()) throw "no valid call";
return std::distance(a.begin(), rit.base()) - 1;
}
template <std::size_t N, typename Callable, typename Tuple>
constexpr std::size_t max_invocable_args()
{
return max_invocable_args<Callable, Tuple>(std::make_index_sequence<N + 1{});
}
// Call taking some element from tuple
template< typename Callable, std::size_t... Is, typename Tuple >
void Call_Tuple_impl(Callable cb, std::index_sequence<Is...>, Tuple&& args )
{
std::invoke(cb, std::get<Is>(std::forward<Tuple>(args))...);
}
template< typename Callable, typename ...Args >
void Call( Callable cb, Args... args )
{
constexpr std::size_t max_arg_count = max_invocable_args<sizeof...(Args), Callable, std::tuple<Args...>>();
Call_Tuple_impl(cb, std::make_index_sequence<max_arg_count>{}, std::forward_as_tuple(std::forward<Args>(args)...));
}
C++20 Demo C++20 演示
C++17 Demo with rewritten constexpr
find
. C++17重写
constexpr
find
的演示。
Break it into two pieces.把它分成两部分。 First, determine how many arguments. Then invoke with that many arguments.
首先,确定有多少 arguments。然后用那么多 arguments 调用。
template<class Tup, std::size_t...Is>
auto slice_tuple(Tup tup, std::index_sequence<Is...>){
using std::get;
return std::make_tuple(get<Is>(std::forward<Tup>(tup))...);
}
template<std::size_t N, class Tup>
auto front_of_tuple(Tup tup){
return slice_tuple(std::forward<Tup>(tup), std::make_index_sequence<N>{});
}
pack up the args into a tuple, get the front N, then std apply.将args打包成元组,获取前面的N,然后std apply。
To perfect forward/avoid copies, use reference wrappers.要完善转发/避免复制,请使用参考包装器。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.