Templates
- Most of the cost for using templates is paid at compile time
- A template is instantiated at compile time
- create a cookie cutter, which is a class
Template Class with a Specialized Method
#include <iostream>
template <class T> // "class" or "typename"
class Widget
{
public:
void print()
{
std::cout << "generic print" << std::endl;
}
};
template <>
void Widget<int>::print()
{
std::cout << "specific print" << std::endl;
}
int main()
{
Widget<float> widget1;
widget1.print();
Widget<int> widget2;
widget2.print();
}
Template Class with a Templated Method
#include <iostream>
template<class T> // "class" or "typename"
class Widget
{
public:
template<class M>
void print(M data);
};
// NOT specialization because no constraints on the T or M
template <class T> // refers to the class
template <class M> // refers to the method
void Widget<T>::print(M data)
{
std::cout << data << std::endl;
}
// specialization!
template <>
template <>
void Widget<int>::print(int data)
{
std::cout << "int:" << data << std::endl;
}
int main()
{
Widget<void> widget1;
widget1.print(0.1f);
Widget<void> widget2;
widget2.print(1);
Widget<int> widget3;
widget3.print(1);
}
Template Class with a Class Partial Specialization
#include <iostream>
#include <vector>
template <class T>
class Widget
{
public:
Widget(T x) : data(x) {}
void print()
{
std::cout << data << std::endl;
}
private:
T data;
};
// a class partial specialization
template <class X>
class Widget<std::vector<X>> // notice this
{
public:
Widget(std::vector<X> xs) : data(xs) {}
void print()
{
for (auto& x : data) std::cout << x << " ";
std::cout << std::endl;
}
private:
std::vector<X> data;
};
int main()
{
Widget<int> widget1(1); // T is int
widget1.print();
Widget<std::vector<int>> widget2({1, 2, 3}); // X is int
widget2.print();
}
NOTE: Only templated classes may be partially specialized; templated methods must be fully specialized.
Variadic Templates, Parameter Pack
template<typename ... Ts>
class Widget;
Solve sum example:
template <typename T>
T adder(T first)
{
return first;
}
template <typename T, typename ... Args> // parameter pack Args
T adder(T first, Args ... args) // parameter pack args
{
return first + adder(args...);
}
int main()
{
std::cout << adder(1, 2) << std::endl;
std::cout << adder(1, 2, 4, 5) << std::endl;
}
Forwarding Reference
- a declaration using data type of
Widget &&- normally an rvalue reference
- but it might not be if
Widgetis a template parameter or auto(the compiler has the option to discard one of the ampersands)
- C++11 intentionally overloaded this syntax
- the community made up a term of: universal reference
- C++ committee has saind forwarding reference is a more accurate term
Perfect Forwarding
- refers to a template function or method which passes arguments
- to another function or method
- preserving the const qualifier and lvalue/rvalue category
std::forwardinstead ofstd::movestd::movewill force the value categary to rvaluestd::forwardconverts the value categary to rvalue only if the original argument was an rvalue
Data Type Deduction
- templates
- T and Parameter-Type may not be deduced as the same data type
- Paramter-Type can include qualifiers like const or a reference
template<typename T>
void func(Parameter-Type var);
Examples
Deduce const:
template <typename T>
void func(T& var)
{
// var is const int
}
int main()
{
const int x = 666;
func(x);
}
Forwarding reference:
template <typename T>
void func(T&& var)
{
}
int main()
{
func(42); // rvalue
int x = 52;
func(x); // lvalue
}