======== Variadic ======== .. contents:: Table of Contents :backlinks: none Variadic Function ----------------- .. code-block:: cpp #include template int sum(T x) { return x; } template int sum(T x, Args ...args) { return x + sum(args...); } int main(int argc, char *argv[]) { std::cout << sum(1, 2, 3, 4, 5) << std::endl; } By using C++17 or above, Fold expression can simplify the previous snippet. .. code-block:: cpp #include template int sum(Args ...args) { return (args + ...); } int main(int argc, char *argv[]) { std::cout << sum(1, 2, 3, 4, 5) << std::endl; } Generic lambda expressions -------------------------- C++14 allows lambda function using ``auto`` type-specifier in the arguments, which is similar to a template function. .. code-block:: cpp #include template auto sum(T x) { return x; } template auto sum(T x, Args ...args) { return x + sum(args...); } int main(int argc, char *argv[]) { auto s = [](auto ...args) { return sum(args...); }; std::cout << s(1, 2, 3, 4, 5) << std::endl; } By using C++17 or above, a programmer can simplify the previous code as following snippet. .. code-block:: cpp // g++ -std=c++17 -Wall -Werror -O3 a.cc #include int main(int argc, char *argv[]) { auto sum = [](auto ...args) { return (args + ...); }; std::cout << sum(1, 2, 3, 4, 5) << std::endl; } Variadic constructor -------------------- .. code-block:: cpp #include #include class Foo { public: template Foo(Args ...args) { Sum(args...); } template void Sum(T t) { sum += t; } template void Sum(T t, Args ...args) { sum += t; Sum(args...); } void Print() { std::cout << sum << std::endl; } private: int sum = 0; }; int main(int argc, char *argv[]) { auto f = Foo(1, 2, 3, 4, 5); f.Print(); } .. code-block:: cpp #include #include class Foo { public: template Foo(T t) { sum += t; } template Foo(T t, Args ...args) : Foo(args...) { sum += t; } void Print() { std::cout << sum << std::endl; } private: int sum = 0; }; int main(int argc, char *argv[]) { auto f = Foo(1, 2, 3, 4, 5); f.Print(); } .. warning:: Please don't invoke a template constructor in a contructor because a new object will be created instead of updating the current object's status. .. code-block:: cpp #include #include class Foo { public: template Foo(T t) { sum += t; } template Foo(T t, Args ...args) { sum += t; Foo(args...); } void Print() { std::cout << sum << std::endl; } private: int sum = 0; }; int main(int argc, char *argv[]) { auto f = Foo(1, 2, 3, 4, 5); f.Print(); } .. code-block:: cpp #include #include class Foo { public: template Foo(Args ...args) { sum = (args + ...); } void Print() { std::cout << sum << std::endl; } private: int sum = 0; }; int main(int argc, char *argv[]) { auto f = Foo(1, 2, 3, 4, 5); f.Print(); } Static Loop unrolling --------------------- .. code-block:: cpp #include #include template struct Loop { template static void run(F &&f, Args&& ...args) { Loop::run(std::forward(f),std::forward(args)...); f(args..., N-1); } }; template <> struct Loop<0> { template static void run(F &&f, Args&& ...args) {} }; int main(int argc, char *argv[]) { size_t counter = 0; // for (int i = 0; i < 5; ++i) { counter += i; } Loop<5>::run([&](auto i) { counter += i; }); std::cout << counter << std::endl; } Fold expression --------------- .. code-block:: cpp #include #include int main(int argc, char *argv[]) { [](auto ...args) { return (args + ...); }(1, 2, 3 ,4 ,5); std::vector v; [](auto &&v, auto ...args) { (v.emplace_back(args), ...); }(v); [](auto ...args) { (std::cout << ... << args) << "\n"; }(1, 2, 3, 4, 5); [](auto &&f, auto ...args) { return (... + f(args)); }([](auto x) { return x * 2; }, 1, 2, 3, 4, 5); }