/*
 * Przykłady użycia Fold Expression.
 * Autor: Łukasz Jaremek
 *
 * Przydatne materiały:
 *     https://en.cppreference.com/w/cpp/language/fold
 *     https://infotraining.bitbucket.io/cpp-17/fold-expressions.html
 */
#include <vector>
#include <iostream>
#include <cmath>

using namespace std;


// Fundamentalne przykłady użycia Fold Expressions
template<typename... Args>
auto sum_numbers(Args... args) {
    return (args + ...);
}

template<typename... Args>
auto product_numbers(Args... args) {
    return (args * ...);
}

template<typename... Args>
bool any(Args... args) {
    return (args || ...);
}

template<typename... Args>
bool all(Args... args) {
    return (args && ...);
}


// Przykłady użycia Fold Expressions
template <typename... Args>
double avg(Args... args) {
    return static_cast<double>((args + ...)) / sizeof...(args);
}

template <typename... Args>
double mean_square(Args... args) {
    return std::sqrt(avg(args * args...));
}

template<typename... Args>
bool equal(Args... args) {
    return ((args == args) && ...);
}

template<typename... Args>
int sum_even(Args... args) {
    return (0 + ... + (args % 2 == 0 ? args : 0));
}

template<typename... Args>
void print(Args... args) {
    ((std::cout << args << " "), ...);
    std::cout << std::endl;
}


int main() {
    // Fundamentalne przykłady użycia Fold Expressions
    std::cout << sum_numbers(1, 2, 3, 4, 5) << std::endl;

    std::cout << product_numbers(1, 2, 3, 4, 5) << std::endl;

    std::cout << any(false, false, false, true, false) << std::endl;

    std::cout << all(true, false, true, true) << std::endl;

    std::cout << std::endl;

    // Przykłady użycia Fold Expressions
    std::cout << avg(0, 5, 10, 15, 20) << std::endl;

    std::cout << mean_square(7, 4, 5, 0, 2, 6) << std::endl;

    std::cout << equal("pies", "pies", "pies", "pies") << std::endl;

    std::cout << sum_even(0, 1, 2, 3, 4, 5, 6, 7, 8, 9) << std::endl;

    print(3, 5, 7);

    return 0;
}
