如何迭代参数包

How to Iterate over a parameter pack

我需要用 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 迭代参数包是正确且唯一的方法吗?

要使用 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)...);
}