Variadic¶
Variadic Function¶
#include <iostream>
template <typename T>
int sum(T x)
{
return x;
}
template <typename T, typename ...Args>
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.
#include <iostream>
template <typename ...Args>
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.
#include <iostream>
template <typename T>
auto sum(T x)
{
return x;
}
template <typename T, typename ...Args>
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.
// g++ -std=c++17 -Wall -Werror -O3 a.cc
#include <iostream>
int main(int argc, char *argv[])
{
auto sum = [](auto ...args) { return (args + ...); };
std::cout << sum(1, 2, 3, 4, 5) << std::endl;
}
Variadic constructor¶
#include <iostream>
#include <vector>
class Foo {
public:
template <typename ...Args>
Foo(Args ...args)
{
Sum(args...);
}
template <typename T>
void Sum(T t)
{
sum += t;
}
template <typename T, typename ...Args>
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();
}
#include <iostream>
#include <vector>
class Foo {
public:
template <typename T>
Foo(T t)
{
sum += t;
}
template <typename T, typename ...Args>
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.
#include <iostream>
#include <vector>
class Foo {
public:
template <typename T>
Foo(T t)
{
sum += t;
}
template <typename T, typename ...Args>
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();
}
#include <iostream>
#include <vector>
class Foo {
public:
template <typename ...Args>
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¶
#include <iostream>
#include <utility>
template <size_t N>
struct Loop {
template <typename F, typename ...Args>
static void run(F &&f, Args&& ...args)
{
Loop<N-1>::run(std::forward<F>(f),std::forward<Args>(args)...);
f(args..., N-1);
}
};
template <>
struct Loop<0> {
template <typename F, typename ...Args>
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¶
#include <iostream>
#include <vector>
int main(int argc, char *argv[])
{
[](auto ...args) {
return (args + ...);
}(1, 2, 3 ,4 ,5);
std::vector<int> 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);
}