Chapter4 Variadic Templates
Fold Expression (Since C++17)
例如,在有fold表达式支持时,可以这样写:
template<typename... Args>
void print(Args... args)
{
(std::cout << ... << args);
}
然而,在此之前要繁琐一些
template<typename... Args>
void print(Args... args)
{
int arr[] = {((std::cout << args), 0)...};
}
fold表达式的详细简绍参考n4659: expr.prim.fold,或者自行Google。
Variadic Indices
一个例子:
template<size_t... Args> struct seq {};
template<size_t N, size_t... Index> struct make_seq
{
using type = typename make_seq<N - 1, N - 1, Index...>::type;
};
template<size_t... Index> struct make_seq<0, Index...>
{
using type = seq<Index...>;
};
template<typename T> struct add_space
{
add_space(const T& t) : t_{t} {}
const T& t_;
friend std::ostream& operator<< (std::ostream& os, add_space<T> x)
{
return os << x.t_ << ' ';
}
};
template<size_t... Idx> void print(seq<Idx...>)
{
(std::cout << ... << add_space(Idx)) << '\n';
}
int main()
{
print(make_seq<10>::type{}); // print `0 1 2 3 4 5 6 7 8 9`
}
variadic indices
常常与std::tuple
、std::variant
、std::get
等一起使用。
Variadic Deduction Guide
C++17允许将类型推导运用于可变参数,例如:
#include <type_traits>
template<typename T, int N>
struct Array
{
template<typename A, typename... Args>
Array(A a, Args... args)
: arr_{a, args...}
{}
T arr_[N];
};
int main()
{
Array arr {1, 2, 3, 4, 5}; // no implicit deduction guide available.
}
尝试编译会出现一下错误
x.cc: In function ‘int main()’:
x.cc:17:27: error: class template argument deduction failed:
Array arr {1, 2, 3, 4, 5};
^
x.cc:17:27: error: no matching function for call to ‘Array(int, int, int, int, int)’
x.cc:7:3: note: candidate: template<class T, int N, class A, class ... Args> Array(A, Args ...)-> Array<T, N>
Array(A a, Args... args)
^~~~~
x.cc:7:3: note: template argument deduction/substitution failed:
x.cc:17:27: note: couldn't deduce template parameter ‘T’
Array arr {1, 2, 3, 4, 5};
注意到错误提示中这句话note: candidate: template<class T, int N, class A, class ... Args> Array(A&&, Args ...)-> Array<T, N>
,这说明编译器尝试推导variadic template,但是失败了。这是就需要显示的告诉编译器正确的推导规则:
template<typename T, typename... U> Array(T, U...) -> Array<std::enable_if_t<(std::is_same_v<T, U> && ...), T>, (1 + sizeof...(U))>;
其中enable_if_t
利用SFINAE确保所有可变参数都是同一类型的(std::is_same_v<T, U> && ...)
则是利用fold expression
完成对所有参数的检查,最后(1 + sizeof...(U))
则确定Array的大小。
Variadic Base Classes
- CTRP
- 前面的note有简绍过 https://note.isliberty.me/2017/04/16/cpp-daily/
- 前面的note有简绍过 https://note.isliberty.me/2017/04/16/cpp-daily/
- C++17
- 之前写的typelist也有用过,见 https://github.com/abbycin/tools/blob/master/typelist.cpp
struct overloaded
- 之前写的typelist也有用过,见 https://github.com/abbycin/tools/blob/master/typelist.cpp