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

发布于 2025-02-04 10:42:50 字数 869 浏览 6 评论 0原文

我正在尝试从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整数值,因此我可以在模板或类似的内容中使用它们。

I'm trying to remove an element from a C++ pack. It's a hard to explain with words so I will just show you what I want in code.

// 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...);
}

I want a pure C++ solution without including any files because it should work for kernel mode and you can't include any standard C++ library in kernel mode.

Any ideas how to do it?

EDIT:
The indices are constexpr integer values so I can use them in templates or anything like that.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

夢归不見 2025-02-11 10:42:50

这是C ++ 20解决方案,无需使用任何标准库标头。

它定义了类型特质,该从包装的前部收集n类型的列表,然后使用列表来定义lambda,该lambda分区foo2 并在每次递归中删除n th索引,直到在委派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{});
}

Here's a C++20 solution without using any standard library headers.

It defines a type trait take which collects a list of N types from the front of a pack, and then uses the list to define a lambda that partitions the arguments of foo2 and drops the Nth index at each recursion until no drop indices are left before delegating to 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{});
}
所有深爱都是秘密 2025-02-11 10:42:50

我找到了一个解决方案,这并不是我想要的,因为它使用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和第三元素将从包中删除(函数调用中的第一个元组),这意味着20.0和<代码> 29.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();
};

I found a solution, it's not exactly what I wanted because it uses std::tuple but it's good enough for now. Here is the code:

#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))
                );
            }
        }
    }
};

Then you can call the function for example like this:

// 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()
    );

In this example the 0 and 3rd element will be removed from the pack (first tuple in the function call) which means 20.0 and 29.0 will be excluded and add2 will be called with 30.0 and 40.0.

EDIT:
I forgot to post this part of the code:

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();
};
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文