繁体   English   中英

如何从 C++ 中的包中删除元素?

[英]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.029.0将被排除,并且add2将使用30.040.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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM