======== Template ======== .. contents:: Table of Contents :backlinks: none Instantiate a Template ---------------------- .. code-block:: cpp #include struct A {}; struct B {}; template struct Foo { Foo(T t, U u) : t_(t), u_(u) {} T t_; U u_; }; template struct Bar { Bar(T t, U u) : f_(t, u) {} F f_; }; // instantiate template Foo template class Foo; int main() { Bar, A, B>(A(), B()); return 0; } Template Specialization ----------------------- .. code-block:: cpp #include template class Base { private: T m_a; U m_b; public: Base(T a, U b) : m_a(a), m_b(b) {}; T foo() { return m_a; } U bar() { return m_b; } }; // partial specialization template class Base { private: T m_a; int m_b; public: Base(T a, int b) : m_a(a), m_b(b) {} T foo() { return m_a; } int bar() { return m_b; } }; // full specialization template<> class Base { private: double d_a; double d_b; public: Base(double a, double b) : d_a(a), d_b(b) {} double foo() { return d_a; } double bar() { return d_b; } }; int main (int argc, char *argv[]) { Base foo(3.33, 1); Base bar(55.66, 95.27); std::cout << foo.foo() << std::endl; std::cout << foo.bar() << std::endl; std::cout << bar.foo() << std::endl; std::cout << bar.bar() << std::endl; return 0; } Class Template -------------- .. code-block:: cpp #include template class Area { protected: T w; T h; public: Area(T a, T b) : w(a), h(b) {} T get() { return w * h; } }; class Rectangle : public Area { public: Rectangle(int a, int b) : Area(a, b) {} }; template class GenericRectangle : public Area { public: GenericRectangle(T a, T b) : Area(a, b){} }; int main (int argc, char *argv[]) { Rectangle r(2, 5); GenericRectangle g1(2.5, 3.); GenericRectangle g2(2, 3); std::cout << r.get() << std::endl; std::cout << g1.get() << std::endl; std::cout << g2.get() << std::endl; return 0; } Variadic Template (Parameter Pack) ---------------------------------- .. code-block:: cpp #include #include #include template class Vector { protected: std::vector v; public: template Vector(Args&&... args) { (v.emplace_back(std::forward(args)), ...); } using iterator = typename std::vector::iterator; iterator begin() noexcept { return v.begin(); } iterator end() noexcept { return v.end(); } }; int main(int argc, char *argv[]) { Vector v{1,2,3}; for (const auto &x : v) { std::cout << x << "\n"; } } Fold expressions ---------------- .. code-block:: cpp // g++ -std=c++17 -Wall -Werror -O3 a.cc #include #include template decltype(auto) f(Args&& ...args) { auto l = [](auto &&x) { return x * 2; }; return (l(std::forward(args)) + ...); } int main(int argc, char *argv[]) { std::cout << f(1, 2, 3, 4, 5) << std::endl; } Limit a Template Types ---------------------- .. code-block:: cpp #include #include #include template::type >::value >::type > void Foo(S s) { std::cout << s << "\n"; } int main(int argc, char *argv[]) { std::string s1 = "Foo"; const std::string s2 = "Bar"; Foo(s1); Foo(s2); // Foo(123); compile error // Foo("Baz"); compile error } Specialize Types ---------------- .. code-block:: cpp #include #include #include template void Foo(S s) { if (std::is_integral::value) { std::cout << "do a task for integer..." << "\n"; return; } if (std::is_same::type>::value) { std::cout << "do a task for string..." << "\n"; return; } } int main(int argc, char *argv[]) { std::string s1 = "Foo"; Foo(s1); Foo(123); } Template Specialization approach .. code-block:: cpp #include #include #include template void Foo(S s) {} template <> void Foo(int s) { std::cout << "do a task for integer..." << "\n"; } template<> void Foo(std::string s) { std::cout << "do a task for string..." << "\n"; } int main(int argc, char *argv[]) { std::string s1 = "Foo"; Foo(s1); Foo(123); } Curiously recurring template pattern ------------------------------------ .. code-block:: cpp #include // Curiously Recurring Template Pattern (CRTP) template class Base { public: void interface() { static_cast(this)->implement(); } static void static_interface() { D::static_interface(); } void implement() { std::cout << "Base" << std::endl; } }; class DerivedFoo : public Base { public: void implement() { std::cout << "Foo" << std::endl; } static void static_interface() { std::cout << "Static Foo" << std::endl; } }; class DerivedBar : public Base {}; int main (int argc, char *argv[]) { DerivedFoo foo; DerivedBar bar; foo.interface(); foo.static_interface(); bar.interface(); return 0; } Parametric Expressions ---------------------- .. code-block:: cpp #include // g++ -std=c++17 -fconcepts -g -O3 a.cpp decltype(auto) min(auto&& lhs, auto&& rhs) { return lhs < rhs ? lhs : rhs; } int main(int argc, char *argv[]) { std::cout << min(1, 2) << "\n"; std::cout << min(3.14, 2.718) << "\n"; } .. code-block:: cpp #include template decltype(auto) min(T&& lhs,T&& rhs) { return lhs < rhs ? lhs : rhs; } int main(int argc, char *argv[]) { std::cout << min(1, 2) << "\n"; std::cout << min(3.14, 2.718) << "\n"; } .. code-block:: cpp #include auto min = [](auto&& lhs, auto&& rhs) { return lhs < rhs ? lhs : rhs; }; int main(int argc, char *argv[]) { std::cout << min(1, 2) << "\n"; std::cout << min(3.14, 2.718) << "\n"; } Reference _ `Parametric Expressions`_ .. _Parametric Expressions: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p1221r0.html Template Template Parameters ---------------------------- .. code-block:: cpp #include #include template class V, class T, class A> void f(V &v) { v.pop_back(); } int main(int argc, char *argv[]) { std::vector v{0}; std::deque q{1}; f(v); f(q); } Access Protected Membors in Sub-Template ---------------------------------------- Accessing protected members by pulling the names into the current scope via ``using``. .. code-block:: cpp #include template class A { public: A(T p) : p_{p} {} decltype(auto) f() { std::cout << p_ << "\n"; } protected: T p_; }; template class B : A { using A::p_; public: B(T p) : A(p) {} decltype(auto) g() { std::cout << p_ << "\n"; } }; int main(int argc, char *argv[]) { A a(0); B b(0); a.f(); b.g(); } Another option is qualifying name via the ``this`` pointer. .. code-block:: cpp #include template class A { public: A(T p) : p_{p} {} decltype(auto) f() { std::cout << p_ << "\n"; } protected: T p_; }; template class B : A { public: B(T p) : A{p} {} decltype(auto) g() { std::cout << this->p_ << "\n"; } }; int main(int argc, char *argv[]) { A a(0); B b(0); a.f(); b.g(); }