可变参数模板:组中展开参数

Fou*_*met 16 c++ templates variadic-templates c++11

我有一个带有两个参数的函数:

template <typename T1, typename T2>
void foo(T1 arg1, T2 arg2)
{ std::cout << arg1 << " + " << arg2 << '\n'; }
Run Code Online (Sandbox Code Playgroud)

一个可变参数的参数应该成对转发:

template <typename... Args>
void bar(Args&&... args) {
    static_assert(sizeof...(Args) % 2 == 0);

    ( foo( std::forward<Args>(args), std::forward<Args>(args) ), ... );
    // ^ Sends each argument twice, not in pairs
}
Run Code Online (Sandbox Code Playgroud)

我想bar(1,2,3,4)打电话foo(1,2)foo(3,4)

有没有办法做到这一点 ?

son*_*yao 13

您可以通过重载来完成它。

template <typename T1, typename T2>
void bar(T1&& arg1, T2&& arg2) {
    foo( std::forward<T1>(arg1), std::forward<T2>(arg2) ); // (until) sends (the last) two arguments to foo
}

template <typename T1, typename T2, typename... Args>
void bar(T1&& arg1, T2&& arg2, Args&&... args) {
    foo( std::forward<T1>(arg1), std::forward<T2>(arg2) ); // sends the 1st two arguments to foo
    bar( std::forward<Args>(args)... );                    // call bar with remaining elements recursively
}
Run Code Online (Sandbox Code Playgroud)

生活


请注意,使用bar0或奇数参数进行调用时,使用上面的最小代码段,您将不会获得匹配的函数错误。如果您希望获得更清晰的编译消息,则static_assert可以从以下代码段开始。


And*_*dyG 5

简单的递归使用if constexpr

// print as many pairs as we can
template<class T, class U, class... Args>
void foo(T t, U u, Args&&... args)
{
    std::cout << t << " + " << u << "\n";
    if constexpr(sizeof...(Args) > 0 && sizeof...(Args) % 2 == 0)
        foo(std::forward<Args>(args)...);
}

template<class... Args>
void bar(Args&&... args)
{
    static_assert(sizeof...(Args) % 2 == 0);
    foo(std::forward<Args>(args)...);
}
Run Code Online (Sandbox Code Playgroud)

这样称呼它:

bar(1, 2, 3, 4);
Run Code Online (Sandbox Code Playgroud)

演示版

我会说Songyanyao的答案是C ++ 17之前的规范。之后,if constexpr允许我们将逻辑移入函数的主体,而不是使用重载技巧。