如何迭代参数包

发布于 2025-01-23 15:11:33 字数 619 浏览 5 评论 0原文

我需要用C ++ 14定义一个具有模板参数包的函数。

函数的呼叫者确保args ...的大小必须是偶数,例如2、4、6 ...,我的功能将传递两到两个函数。

template<typename F, typename F2, typename... Args>
void func(F f, F2 f2, Args&&... params) {
    using params_t = std::tuple<Args...>;
    auto tp = std::make_tuple(params...);
    for (std::size_t i = 0; i < sizeof...(Args); ++i) {
        f(std::get<i>(tp));
        f2(std::get<++i>(tp));
    }
}

// caller
func(f1, f2, "abc", 3, "def", "ppp");

这是不起作用的,因为i不是恒定的表达式。

我该怎么办?这是使用std :: tuple迭代参数包的正确和唯一方法?

I need to define a function with template parameter pack with C++14.

The caller of the function makes sure that the size of Args... must be even, such as 2, 4, 6... And my function will pass them two by two to two functions.

template<typename F, typename F2, typename... Args>
void func(F f, F2 f2, Args&&... params) {
    using params_t = std::tuple<Args...>;
    auto tp = std::make_tuple(params...);
    for (std::size_t i = 0; i < sizeof...(Args); ++i) {
        f(std::get<i>(tp));
        f2(std::get<++i>(tp));
    }
}

// caller
func(f1, f2, "abc", 3, "def", "ppp");

This won't work because i is not a constant expression.

What could I do? Is it the right and the only way to iterate over a parameter pack with std::tuple?

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

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

发布评论

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

评论(2

泡沫很甜 2025-01-30 15:11:33

要使用std :: tuple在参数包上迭代,通常您会使用 std :: index_sequence 引入一包新的索引,并使用折叠表达式进行实际迭代。类似的东西:

template<typename F, typename F2, typename... Args, std::size_t... I>
void func_impl(F& f, F2& f2, std::tuple<Args...> params, std::index_sequence<I...>) {
    // This would be a fold expression over a comma in C++17:
    /*
    (([&]{}(
        f(std::get<I*2>(params));
        f2(std::get<I*2+1>(params));
    )), ...);
    */
    // C++14 version
    using consume = int[];
    (void) consume{ 0, [&]{
        f(std::get<I*2>(params));
        f2(std::get<I*2+1>(params));
        return 0;
    }()... };
}

template<typename F, typename F2, typename... Args>
void func(F f, F2 f2, Args&&... args) {
    static_assert(sizeof...(args) % 2 == 0, "Must pass a multiple of 2 args to func");
    func_impl(
        f, f2,
        std::forward_as_tuple(std::forward<Args>(args)...),
        std::make_index_sequence<sizeof...(args) / 2>{}
    );
}

但是您也可以通过递归迭代,这在您的情况下可能更容易:

template<typename F, typename F2>
void func(F&& f, F2&& f2) {
    // base case: do nothing
}

template<typename F, typename F2, typename Arg1, typename Arg2, typename... Args>
void func(F&& f, F2&& f2, Arg1&& arg1, Arg2&& arg2, Args&&... args) {
    // recursive case
    f(arg1);
    f2(arg2);
    func(std::forward<F>(f), std::forward<F2>(f2), std::forward<Args>(args)...);
}

To use a std::tuple to iterate over a parameter pack, you would usually use a std::index_sequence to introduce a new pack of indices, and use a fold expression to do the actual iteration. Something like this:

template<typename F, typename F2, typename... Args, std::size_t... I>
void func_impl(F& f, F2& f2, std::tuple<Args...> params, std::index_sequence<I...>) {
    // This would be a fold expression over a comma in C++17:
    /*
    (([&]{}(
        f(std::get<I*2>(params));
        f2(std::get<I*2+1>(params));
    )), ...);
    */
    // C++14 version
    using consume = int[];
    (void) consume{ 0, [&]{
        f(std::get<I*2>(params));
        f2(std::get<I*2+1>(params));
        return 0;
    }()... };
}

template<typename F, typename F2, typename... Args>
void func(F f, F2 f2, Args&&... args) {
    static_assert(sizeof...(args) % 2 == 0, "Must pass a multiple of 2 args to func");
    func_impl(
        f, f2,
        std::forward_as_tuple(std::forward<Args>(args)...),
        std::make_index_sequence<sizeof...(args) / 2>{}
    );
}

But you can also iterate with recursion, which might be easier in your case:

template<typename F, typename F2>
void func(F&& f, F2&& f2) {
    // base case: do nothing
}

template<typename F, typename F2, typename Arg1, typename Arg2, typename... Args>
void func(F&& f, F2&& f2, Arg1&& arg1, Arg2&& arg2, Args&&... args) {
    // recursive case
    f(arg1);
    f2(arg2);
    func(std::forward<F>(f), std::forward<F2>(f2), std::forward<Args>(args)...);
}
嘿咻 2025-01-30 15:11:33

这是我在2011年有限的C ++的情况下做的类型的样本:
(没有 lambdas nor std :: tuple

#include <iostream>
using namespace std ;

static int count ()
    {
    return 0 ;
    }

template <class HEAD,class...TAIL> int count ( const HEAD & , const TAIL & ...tail )
    {
    return count( tail... )+1 ;
    }


template <class FONCTOR> int apply_fonctor ( const FONCTOR & )
    {
    return 0 ;
    }

template <class FONCTOR,class HEAD,class ...TAIL> int apply_fonctor ( const FONCTOR & f , const HEAD & head , const TAIL&...tail )
    {
    f( head ) ;
    return apply_fonctor( f,tail... )+1 ;
    }

struct Eggs 
    {
    int x ;
    Eggs ( int x )          : x(x)                                           {}
    Eggs ( const Eggs & e ) : x(e.x)                                         { cout << "### Eggs duplicated" ;}
    Eggs & operator= ( const Eggs & e )                                      { cout << "### Eggs copied" ; x = e.x ;}
    template<class OUT> friend OUT & operator<< ( OUT & o , const Eggs & e ) { o << "egg=" << e.x ; return o ;}
    };

struct Functor
    {
    void operator() ( int    p )       const { cout << " [" << p << "] " ;}
    void operator() ( bool   p )       const { cout << " [" << (p?"true":"false") << "] " ;}
    void operator() ( double p )       const { cout << " [" << p << "] " ;}
    void operator() ( const char * p ) const { cout << " [" << p << "] " ;}
    void operator() ( const Eggs & p ) const { cout << " [" << p << "] " ;}
    };

void main ()
    {       
    Eggs e(42) ;
    cout << "count = " << count() << endl ;
    cout << "count = " << count( "just one" ) << endl ;
    cout << "count = " << count( 42,"spam",3.14159,false,e,12345678901234567890ull ) << endl ;

    cout << "Calls of functor :" ;
    Functor f ;
    int nb = apply_fonctor( f,e,123,"bread",true,1.4142 ) ;
    cout << "\n applied to " << nb << endl ;
    //apply_fonctor( f,12345678901234567890ull ) ; // <--- won't commpile because Functor does not handle ULL
    }

有第一个示例执行参数的简单计数,
和第二个样本,演示了如何在每个参数上应用A fuctor

NB:最终eggs复制由 ### 在输出中显示。
- &gt;没有!

输出应为:

count = 1
count = 6
Calls of functor : [egg=42]  [123]  [bread]  [true]  [1.4142]
 applied to 5```

Here is a sample of the the kind of things I do, with my 2011 limited c++ :
(without lambdas nor std::tuple)

#include <iostream>
using namespace std ;

static int count ()
    {
    return 0 ;
    }

template <class HEAD,class...TAIL> int count ( const HEAD & , const TAIL & ...tail )
    {
    return count( tail... )+1 ;
    }


template <class FONCTOR> int apply_fonctor ( const FONCTOR & )
    {
    return 0 ;
    }

template <class FONCTOR,class HEAD,class ...TAIL> int apply_fonctor ( const FONCTOR & f , const HEAD & head , const TAIL&...tail )
    {
    f( head ) ;
    return apply_fonctor( f,tail... )+1 ;
    }

struct Eggs 
    {
    int x ;
    Eggs ( int x )          : x(x)                                           {}
    Eggs ( const Eggs & e ) : x(e.x)                                         { cout << "### Eggs duplicated" ;}
    Eggs & operator= ( const Eggs & e )                                      { cout << "### Eggs copied" ; x = e.x ;}
    template<class OUT> friend OUT & operator<< ( OUT & o , const Eggs & e ) { o << "egg=" << e.x ; return o ;}
    };

struct Functor
    {
    void operator() ( int    p )       const { cout << " [" << p << "] " ;}
    void operator() ( bool   p )       const { cout << " [" << (p?"true":"false") << "] " ;}
    void operator() ( double p )       const { cout << " [" << p << "] " ;}
    void operator() ( const char * p ) const { cout << " [" << p << "] " ;}
    void operator() ( const Eggs & p ) const { cout << " [" << p << "] " ;}
    };

void main ()
    {       
    Eggs e(42) ;
    cout << "count = " << count() << endl ;
    cout << "count = " << count( "just one" ) << endl ;
    cout << "count = " << count( 42,"spam",3.14159,false,e,12345678901234567890ull ) << endl ;

    cout << "Calls of functor :" ;
    Functor f ;
    int nb = apply_fonctor( f,e,123,"bread",true,1.4142 ) ;
    cout << "\n applied to " << nb << endl ;
    //apply_fonctor( f,12345678901234567890ull ) ; // <--- won't commpile because Functor does not handle ULL
    }

There is a first sample performing a simple count of the parameters,
and a second sample demonstrating how to apply a functor on each parameter.

NB : Eventual Eggs copy is revealed by ### in the output.
--> there is none !

The output should be:

count = 1
count = 6
Calls of functor : [egg=42]  [123]  [bread]  [true]  [1.4142]
 applied to 5```
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文