实现左右折叠的可变参数模板的最佳方法是什么

发布于 2025-01-11 05:13:10 字数 537 浏览 2 评论 0原文

的形式

template<typename ...args>
void func(int l, args... arg, int r){

}

我正在尝试实现一些我可以使用

template<typename ...args>
void func(int l, int r, args... arg){

}

,但这会使它使用起来更加不直观。 该函数本身是

    template<typename ...TA, enable_if_t<sizeof...(TA) == 2 * (d - 1), int> = 0>
    void upd(int u1, TA... args, T val){
        u1 += n;
        while(u1){
            t[u1].upd(args..., val);
            u1 >>= 1;
        }
    }

I'm trying to implement something of the form

template<typename ...args>
void func(int l, args... arg, int r){

}

I could use

template<typename ...args>
void func(int l, int r, args... arg){

}

but it would make it far more unintuitive to use.
The function itself is

    template<typename ...TA, enable_if_t<sizeof...(TA) == 2 * (d - 1), int> = 0>
    void upd(int u1, TA... args, T val){
        u1 += n;
        while(u1){
            t[u1].upd(args..., val);
            u1 >>= 1;
        }
    }

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

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

发布评论

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

评论(1

暖风昔人 2025-01-18 05:13:10

d 似乎是固定的,因此它并不是真正的可变参数。

然后您可以进行专门化(达到一定限制)

template <std::size_t d>
struct S;

template <>
struct S<0>
{
    void upd(int u1, T val){
        u1 += n;
        while(u1){
            t[u1].upd(val);
            u1 >>= 1;
        }
    }
};

template <>
struct S<1>
{
    template <typename T1, typename T2>
    void upd(int u1, T1 t1, T2 t2, T val){
        u1 += n;
        while(u1){
            t[u1].upd(T1, t2, val);
            u1 >>= 1;
        }
    }
};

//...
// struct S<2>
// ...
// void upd(int u1, T1 t1, T2 t2, T3 t3, T4 t4, T val){
// ...

如果类型 T1、TN 是固定的(假设 SomeType),一种可能性是使用 std::index_sequence 而不是 d


template <std::size_t, typename T>
using always_t = T;

template <typename Seq>
struct S_impl;

template <std::size_t... Is>
struct S_impl<std::index_sequence<Is...>>
{
    void upd(int u1, always_t<Is, SomeType>... args, T val){
        u1 += n;
        while(u1) {
            t[u1].upd(args..., val);
            u1 >>= 1;
        }
    }
};

template <std::size_t d>
using S = S_impl<std::make_index_sequence<d>>;

否则,您可以使用用于实现的元组或重新排序参数,并为接口提供包装器:

template<std::size_t... Is, typename Tuple>
auto extract(std::index_sequence<Is...>, Tuple t)
{
    return std::tie(std::get<Is>(t)...);
}

template <typename ...Ts, enable_if_t<sizeof...(Ts) == 2 * (d - 1), int> = 0>
void upd_impl(int u1, std::tuple<Ts...> tup, T val) {
    u1 += n;
    while(u1){
        std::apply([&](auto&&... args){
            t[u1].upd(args..., val);
            u1 >>= 1;
        }, tup
    }
}

template <typename ...Ts, enable_if_t<sizeof...(Ts) == 1 + 2 * (d - 1), int> = 0>
void upd(int u1, Ts... args) {
    upd_impl(u1,
             extract(std::make_index_sequence<sizeof...(Ts) - 1>(),
                     std::tie(args...)),
             std::get<sizeof...(Ts) - 1>(std::tie(args...)));
}

d seems fixed, so it is not really variadic.

You can then have specializations (up to a certain limit)

template <std::size_t d>
struct S;

template <>
struct S<0>
{
    void upd(int u1, T val){
        u1 += n;
        while(u1){
            t[u1].upd(val);
            u1 >>= 1;
        }
    }
};

template <>
struct S<1>
{
    template <typename T1, typename T2>
    void upd(int u1, T1 t1, T2 t2, T val){
        u1 += n;
        while(u1){
            t[u1].upd(T1, t2, val);
            u1 >>= 1;
        }
    }
};

//...
// struct S<2>
// ...
// void upd(int u1, T1 t1, T2 t2, T3 t3, T4 t4, T val){
// ...

If the types T1, TN are fixed (assuming SomeType), one possibility is to use std::index_sequence instead of d


template <std::size_t, typename T>
using always_t = T;

template <typename Seq>
struct S_impl;

template <std::size_t... Is>
struct S_impl<std::index_sequence<Is...>>
{
    void upd(int u1, always_t<Is, SomeType>... args, T val){
        u1 += n;
        while(u1) {
            t[u1].upd(args..., val);
            u1 >>= 1;
        }
    }
};

template <std::size_t d>
using S = S_impl<std::make_index_sequence<d>>;

Else, you can use tuple or reordering argument for implementation, and provide wrapper for the interface:

template<std::size_t... Is, typename Tuple>
auto extract(std::index_sequence<Is...>, Tuple t)
{
    return std::tie(std::get<Is>(t)...);
}

template <typename ...Ts, enable_if_t<sizeof...(Ts) == 2 * (d - 1), int> = 0>
void upd_impl(int u1, std::tuple<Ts...> tup, T val) {
    u1 += n;
    while(u1){
        std::apply([&](auto&&... args){
            t[u1].upd(args..., val);
            u1 >>= 1;
        }, tup
    }
}

template <typename ...Ts, enable_if_t<sizeof...(Ts) == 1 + 2 * (d - 1), int> = 0>
void upd(int u1, Ts... args) {
    upd_impl(u1,
             extract(std::make_index_sequence<sizeof...(Ts) - 1>(),
                     std::tie(args...)),
             std::get<sizeof...(Ts) - 1>(std::tie(args...)));
}

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