[英]How to remove an element from a pack in C++?
我正在尝试从 C++ 包中删除一个元素。 这很难用语言来解释,所以我只会用代码告诉你我想要什么。
// lets say I have the following function
template<typename... Args>
void foo1(Args... arguments)
{
// does something with the arguments
}
// and another similar function which needs to call foo1 but with a modified pack
template<typename... Args>
void foo2(Args... arguments)
{
// foo2 figures out what arguments should be removed from the "arguments" pack
// and here comes the hard part, after I know the indices of what elements to remove, how do I remove them from the pack?
// then foo2 calls foo1 with the new pack (modified argument list)
foo1(new_arguments...);
}
我想要一个不包含任何文件的纯 C++ 解决方案,因为它应该适用于内核模式,并且您不能在内核模式中包含任何标准 C++ 库。
任何想法如何做到这一点?
编辑:索引是 constexpr 整数值,所以我可以在模板或类似的东西中使用它们。
这是一个不使用任何标准库头文件的 C++20 解决方案。
它定义了一个类型特征take
,它从包的前面收集N
个类型的列表,然后使用该列表定义一个 lambda,该 lambda 对foo2
的参数进行分区,并在每次递归时删除第N
个索引,直到没有删除索引留下在委托给foo1
之前。
namespace detail {
template <class...>
struct list {};
template <int, class, class = list<>>
struct take;
template <class Drop, class Take>
struct take<0, Drop, Take> {
using type = Take;
};
template <int N, class T, class... Drop, class... Take>
requires(N > 0)
struct take<N, list<T, Drop...>, list<Take...>>
: take<N - 1, list<Drop...>, list<Take..., T>> {};
} // namespace detail
template <class... Args>
void foo2(Args... new_arguments) {
foo1(new_arguments...);
}
template <int Index, int... Indices, class... Args>
void foo2(Args... arguments) {
[&]<class... Take>(detail::list<Take...>) {
[](Take... take, auto, auto... rest) {
foo2<(Indices - 1)...>(take..., rest...);
}(arguments...);
}(typename detail::take<Index, detail::list<Args...>>::type{});
}
我找到了一个解决方案,它不是我想要的,因为它使用std::tuple
但现在已经足够了。 这是代码:
#include <tuple>
struct remove_element_from_pack
{
private:
template<typename Ty, typename... Args>
__forceinline constexpr static Ty get_first_val(Ty val, Args... other) { return val; }
template<typename Ty, typename... Args>
__forceinline constexpr static auto remove_first_from_tuple(Ty first, Args... rest)
{
return std::tuple<Args...>(rest...);
}
template<typename return_ty, typename... Args>
__forceinline constexpr static return_ty call_func_internal(const void* function, Args... arguments)
{
return ((return_ty(__fastcall*)(Args...))function)(arguments...);
}
public:
template<
typename return_ty,
int current_index,
int remove_current,
int... remove,
typename current_ty,
typename... All,
typename... Processed>
__forceinline static return_ty call_func(const void* function, std::tuple<current_ty, All...> all, std::tuple<Processed...> processed)
{
auto current = std::apply([](auto&&... args)->auto { return get_first_val(args...); }, all);
// if there are no more elements
if constexpr (!sizeof...(All))
{
// if we have to remove the current element
if constexpr (remove_current != -1 && is_in_pack<int, current_index, remove_current, remove...>::value)
{
return std::apply(
[](auto &&... args)->return_ty { return call_func_internal<return_ty>(args...); },
std::tuple_cat(std::make_tuple(function), processed)
);
}
else
{
return std::apply(
[](auto &&... args)->return_ty { return call_func_internal<return_ty>(args...); },
std::tuple_cat(std::make_tuple(function), std::tuple_cat(processed, std::make_tuple(current)))
);
}
}
else
{
auto new_all = std::apply([](auto&&... args)->auto { return remove_first_from_tuple(args...); }, all);
// if we have to remove the current element
if constexpr (remove_current != -1 && is_in_pack<int, current_index, remove_current, remove...>::value)
{
// if there are any elements left to remove
if constexpr (sizeof...(remove) > 0)
{
return std::apply(
[](auto &&... args)->return_ty { return call_func<return_ty, current_index + 1, remove...>(args...); },
std::tuple_cat(std::make_tuple(function), std::make_tuple(new_all), std::make_tuple(processed))
);
}
else
{
return std::apply(
[](auto &&... args)->return_ty { return call_func<return_ty, current_index + 1, -1>(args...); },
std::tuple_cat(std::make_tuple(function), std::make_tuple(new_all), std::make_tuple(processed))
);
}
}
else
{
auto new_processed = std::tuple_cat(processed, std::make_tuple(current));
return std::apply(
[](auto &&... args)->return_ty { return call_func<return_ty, current_index + 1, remove_current, remove...>(args...); },
std::tuple_cat(std::make_tuple(function), std::make_tuple(new_all), std::make_tuple(new_processed))
);
}
}
}
};
然后您可以像这样调用该函数:
// target function
int __fastcall add2(double a, double b)
{
return a + b;
}
// call
remove_element_from_pack::call_func<int, 0, 0, 3>(
add2, std::tuple<double, double, double, double>(20.0, 30.0, 40.0, 29.0), std::tuple()
);
在此示例中,将从包中删除第 0 和第 3 个元素(函数调用中的第一个元组),这意味着20.0
和29.0
将被排除,并且add2
将使用30.0
和40.0
调用。
编辑:我忘了发布这部分代码:
template<typename Ty, Ty element, Ty first, Ty... rest_of_pack>
struct is_in_pack
{
private:
__forceinline static constexpr bool get_value_internal()
{
if constexpr (first == element)
return true;
else if constexpr (!sizeof...(rest_of_pack))
return false;
else
return is_in_pack<Ty, element, rest_of_pack...>::value;
}
public:
static constexpr const bool value = get_value_internal();
};
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.