- 
                Notifications
    You must be signed in to change notification settings 
- Fork 0
Templates
- A template is a class or a function that we parameterize with a set of types or values
- It allows us to work with generic types.
- Through templates, rather than repeating function code for each new type we wish to accommodate, we can create functions that are capable of using the same code for different types.
int sum(const int x, const int y) {
    return x + y;
}
double sum (const double x, const double y) {
  return x + y;
}The format for declaring a function template is:
template <typename identifier> function_declaration;So, we rewrite our sum function:
template <typename T>
  T sum(const T a, const T b) {
  return a + b;
}To invoke a function template, we use:
function_name <type> (parameters);For example,
int main() {
 cout << sum<int>(1, 2) << endl;
 cout << sum<float>(1.21, 2.43) << endl;
 return 0;
}- The identifier can be used in any way inside the function template, as long as the code makes sense after identifier is replaced with some type.
- It is also possible to invoke a function template without giving an explicit type, in cases where the generic type identifier is used as the type for a parameter for the function.
int main() {
   cout << sum(1, 2) << endl;
   cout << sum(1.21, 2.43) << endl;
   std::cout<<sum(1,3.9)<<std::endl;  //ERROR no matching function for call to 'sum(int, double)'
   return 0;
 }- Templates can also specify more than one type parameter. For example:
#include <iostream>
#include <string>
template <typename T, typename U>
U sum(const T a, const U b){
    return a + b;
}
int main()
{
 std::cout<<sum<int,float>(1,3.9)<<std::endl;
 std::cout<<sum<float,float>(1,3.9)<<std::endl;
 std::cout<<sum<float,int>(1,3.9)<<std::endl;
 std::cout<<sum(1,3.9)<<std::endl;
 std::cout<<sum(3.9,1)<<std::endl;
}
/*
4.9
4.9
4
4.9
4
*/- Class templates are also possible, in much the same way we have written function templates:
#include <iostream>
#include <string>
using namespace std;
template <typename T>
class Point{
    private:
        T x, y;
    public:
        Point(const T u, const T v){
            x = u;
            y = v;
        }
        T getX() {return x;}
        T getY(){return y;}
};
int main()
{
    Point<float> fpoint(2.5, 3.4);
    Point<int> fpoint2(2.5, 3.4);
    cout<<fpoint.getX()<<", "<<fpoint.getY()<<endl;
    cout<<fpoint2.getX()<<", "<<fpoint2.getY()<<endl;
    return 0;
}
/*
2.5, 3.4
2, 3
*/- To declare member functions externally, we use the following syntax:
template <typename T>
T classname<T>::function_name()For example
template<typename T>
class Vector {
private:
  T∗ elem; // elem points to an array of sz elements of type T
  int sz;
public:
  Vector(int s); // constructor: establish invariant, acquire resources
  ˜Vector() { delete[] elem; } // destructor: release resources
  // ... copy and move operations ...
  T& operator[](int i);
  const T& operator[](int i) const;
  int size() const { return sz; }
};- 
The template<typename T>prefix makesTa parameter of the declaration it prefixes 👊 🌹
- It is C++’s version of the mathematical ‘‘for all T’’ or more precisely ‘‘for all types T.’’
- The member functions might be defined similarly:
template<typename T>
Vector<T>::Vector(int s)
{
  if (s<0) throw Negative_siz e{};
  elem = new T[s];
  sz = s;
}
template<typename T>
const T& Vector<T>::operator[](int i) const
{
  if (i<0 || size()<=i)
  throw out_of_rang e{"Vector::operator[]"};
  return elem[i];
}- Given these definitions, we can define Vectorslike this:
Vector<char> vc(200); // vector of 200 characters
Vector<string> vs(17); // vector of 17 strings
Vector<list<int>> vli(45); // vector of 45 lists of integersWe can use Vectors like this:
void write(const Vector<string>& vs) // Vector of some strings
{
  for (int i = 0; i!=vs.size(); ++i)
  cout << vs[i] << '\n';
}To support the range-for loop for our Vector, we must define suitable begin() and end() functions:
template<typename T>
T∗ begin(Vector<T>& x)
{
  return &x[0]; // pointer to first element
}
template<typename T>
T∗ end(Vector<T>& x)
{
  return x.begin()+x.size(); // pointer to one-past-last element
}Given those, we can write:
void f2(const Vector<string>& vs) // Vector of some strings
{
  for (auto& s : vs)
    cout << s << '\n';
}- Templates are a compile-time mechanism, so their use incurs no run-time overhead compared to ‘‘handwritten code’’ 👊👊
For example, we can write a function that calculates the sum of the element values of any container like this:
template<typename Container, typename Value>
Value sum(const Container& c, Value v)
{
  for (auto x : c)
    v+=x;
  return v;
}void user(Vector<int>& vi, std::list<double>& ld, std::vector<complex<double>>& vc)
{
  int x = sum(vi,0); // the sum of a vector of ints (add ints)
  double d = sum(vi,0.0); // the sum of a vector of ints (add doubles)
  double dd = sum(ld,0.0); // the sum of a list of doubles
  auto z = sum(vc,complex<double>{}); // the sum of a vector of complex<double>
  // the initial value is {0.0,0.0}
}Note how the types of the template arguments for sum<T,V> are deduced from the function
arguments. Fortunately, we do not need to explicitly specify those types 👊❤️
- One particularly useful kind of template is the function object (sometimes called a functor), which is used to define objects that can be called like functions.
template<typename T>
class Less_than {
  const T val; // value to compare against
public:
  Less_than(const T& v) :val(v) { }
  bool operator()(const T& x) const { return x<val; } // call operator
};The function called operator() implements the ‘‘function call,’’ ‘‘call,’’ or ‘‘application’’ operator ().
- We can define named variables of type Less_than for some argument type:
Less_than<int> lti {42}; // lti(i) will compare i to 42 using < (i<42)
Less_than<string> lts {"Backus"}; // lts(s) will compare s to "Backus" using < (s<"Backus")We can call such an object, just as we call a function:
void fct(int n, const string & s)
{
  bool b1 = lti(n); // true if n<42
  bool b2 = lts(s); // true if s<"Backus"
  // ...
}Such function objects are widely used as arguments to algorithms. For example, we can count the
occurrences of values for which a predicate returns true: