C/C++ Arena

Step 1 of 9

Parameter packs and fold expressions

Some functions naturally take any number of arguments: std::make_unique<T>(args...) forwards however many the constructor needs, std::format takes a value for every {}. A variadic template accepts any number of arguments, of any types, as a parameter pack.

#include <iostream>
#include <string>

template <typename... Ts>
auto sum(Ts... xs) {
    return (xs + ...);                     // a fold expression: x1 + (x2 + (x3 + ...))
}

template <typename... Ts>
void print_all(const Ts&... xs) {
    ((std::cout << xs << " "), ...);       // a comma fold: do this for each x, in order
    std::cout << "(" << sizeof...(xs) << " values)\n";
}

template <typename... Ts>
bool any_empty(const Ts&... strs) {
    return (strs.empty() || ...);          // true if at least one is empty
}

int main() {
    std::cout << sum(1, 2, 3) << " " << sum(1.5, 2) << "\n";
    print_all("id", 7, 2.5, 'x');
    std::cout << any_empty(std::string("a"), std::string(""), std::string("c")) << "\n";
}
6 3.5
id 7 2.5 x (4 values)
1

How it works

Your task

For counting, turn each check into a number and add them: (int(pred(xs)) + ... + 0). The + 0 at the end makes the fold work even with zero arguments (an empty + fold with no starting value doesn't compile). all_positive is an && fold of xs > 0, which is true for an empty pack.

Your turn: write count_if_all(pred, xs...), returning how many of the arguments satisfy pred, and all_positive(xs...). Use fold expressions, no loops.

Next: Perfect forwarding