上文书介绍了 C++11 中的右值引用及其应用:移动语义和完美转发。本文介绍另外一个应用广泛的特性,变参模板。变参模板允许模板使用个数可变的参数类型来声明模板,包括类模板和函数模板。变参模板的基本语法是这样的:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | void print() { cout<<endl; } template <typename T, typename... Args> void print(const T &t, const Args&... args) { cout<<t<<" "; print(args...); } int main() { print(123, 3.14, "tair"); return 0; } |
上面实现了一个简单的类型安全的变参打印函数。
结合右值引用,变参模板在 STL 中应用广泛,例如 vector 中的 emplace 函数族(每个 STL 容器都提供了适当接口的 emplace* 函数),用来使用其参数在内部内存单元上直接构造对象,不但避免了不必要的内存拷贝,还可以省去临时对象的构造:
1 2 3 4 5 | template <class... Args> void vector<T>::emplace_back (Args&&... args); std::vector<string> v; v.emplace_back(10, '*'); //~ new(&vec[size()])string(10, '*') |
v.emplace_back(10, ‘*’) 在内部内存上使用 placement new 操作符,直接调用 std::string(size_t n, char c) 来构造对象。
变参模板的另一个应用案例就是 tuple 的实现:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 | template <typename... Rest> struct Tuple; template <> struct Tuple<> {}; template <typename First, typename ... Rest> struct Tuple<First, Rest...> : public Tuple<Rest...> { Tuple() : value() {} Tuple(First &&first, Rest&&... rest) : value(std::forward<First>(first)), Tuple<Rest...>(std::forward<Rest>(rest)...) { } First value; }; template <size_t N, typename TP> struct Tuple_Element; template <typename T, typename ... Rest> struct Tuple_Element<0, Tuple<T, Rest...>> { typedef T type; typedef Tuple<T, Rest...> TPType; }; template <size_t N, typename T, typename ... Rest> struct Tuple_Element<N, Tuple<T, Rest...>> : public Tuple_Element<N - 1, Tuple<Rest...>> { }; template <size_t N, typename ... Rest> typename Tuple_Element<N, Tuple<Rest...>>::type& get(Tuple<Rest...> &tp) { typedef typename Tuple_Element<N, Tuple<Rest...>>::TPType type; return ((type&)tp).value; } int main() { Tuple<int, string, double> tp(3, "2", 1.); cout<<get<0>(tp)<<endl; cout<<get<1>(tp)<<endl; cout<<get<2>(tp)<<endl; return 0; } |