【CPP】类模版

1- Class Templates

Review: Function Templates

  • A function template is not a type, to a function, or any other entity
  • No code is generated from a source file that contains only template definitions
  • The template arguments must be determined, then the compiler can generate an actual function
  • “Function Template” vs “Template Function”
template<typename T>
T sum(T x, T y)
{
  cout << "The input type is " << typeid(T).name() << endl;
  return x + y;
}

// instantiates sum(double, double)
template double sum<double> (double, double);
// instantiates sum (char, char), template argument deduced
template char sum<> (char, char);
// instantiates sum(int, int), template argument deduced
template int sum(int, int);

模版函数是函数模版生成实例化后的具体的函数

  • Implicit instantiation occurs when a function template is not explicitly instantiated
template<typename T>
T sum(T x, T y)
{
  cout << "The input type is " << typeid(T).name() << endl;
  return x + y;
}

// Implicitlyy instantiates product(int, int)
cout << "product = " << product<int>(2.2f, 3.0f) << endl;
// Implicitly instantiates product(float, float)
cout << "product = " << product(2.2f, 3.0f) << endl;

Different Classes for Different Type Matrices

  • Matrix with int elements, Matrix with float elements
    【CPP】类模版_第1张图片

matchless.cpp

#include 
using namespace std;

// Class IntMat
class IntMat
{
    size_t rows;
    size_t cols;
    int * data;
  public:
    IntMat(size_t rows, size_t cols): 
                    rows(rows), cols(cols)
    { 
        data = new int[rows * cols]{};
    }
    ~IntMat()
    {
        delete [] data;
    }
    IntMat(const IntMat&) = delete;
    IntMat& operator=(const IntMat&) = delete;
    int getElement(size_t r, size_t c);
    bool setElement(size_t r, size_t c, int value);
};
int IntMat::getElement(size_t r, size_t c)
{
    if ( r >= this->rows || c >= this->cols)
    {
        cerr << "Indices are out of range" << endl;
        return 0;
    }
    return data[ this->cols * r + c];
}
bool IntMat::setElement(size_t r, size_t c, int value)
{
    if ( r >= this->rows || c >= this->cols)
        return false;

    data[ this->cols * r + c] = value;
    return true;
}

// Class FloatMat
class FloatMat
{
    size_t rows;
    size_t cols;
    float * data;
  public:
    FloatMat(size_t rows, size_t cols): 
                    rows(rows), cols(cols)
    {
        data = new float[rows * cols]{};
    }
    ~FloatMat()
    {
        delete [] data;
    }
    FloatMat(const FloatMat&) = delete;
    FloatMat& operator=(const FloatMat&) = delete;
    float getElement(size_t r, size_t c);
    bool setElement(size_t r, size_t c, float value);
};
float FloatMat::getElement(size_t r, size_t c)
{
    if ( r >= this->rows || c >= this->cols)
    {
        cerr << "getElement(): Indices are out of range" << endl;
        return 0.f;
    }
    return data[ this->cols * r + c];
}
bool FloatMat::setElement(size_t r, size_t c, float value)
{
    if ( r >= this->rows || c >= this->cols)
    {
        cerr << "setElement(): Indices are out of range" << endl;
        return false;
    }
    data[ this->cols * r + c] = value;
    return true;
}

int main()
{
    IntMat imat(3,4);
    imat.setElement(1, 2, 256);
    FloatMat fmat(2,3);
    fmat.setElement(1, 2, 3.14159f);

    // FloatMat fmat2(fmat); //error

    // FloatMat fmat3(2,3); 
    // fmat3 = fmat; //error

    cout << imat.getElement(1,2) << endl;
    cout << fmat.getElement(1,2) << endl;
    
    return 0;
}
256
3.14159

Class Templates

  • A class template defines a family of classes

mat template.cpp

#include 
using namespace std;

// Class Template
template<typename T>
class Mat
{
    size_t rows;
    size_t cols;
    T * data;
  public:
    Mat(size_t rows, size_t cols): rows(rows), cols(cols)
    {
        data = new T[rows * cols]{};
    }
    ~Mat()
    {
        delete [] data;
    }
    Mat(const Mat&) = delete;
    Mat& operator=(const Mat&) = delete;
    T getElement(size_t r, size_t c);
    bool setElement(size_t r, size_t c, T value);
};
template <typename T>
T Mat<T>::getElement(size_t r, size_t c)
{
    if ( r >= this->rows || c >= this->cols)
    {
        cerr << "getElement(): Indices are out of range" << endl;
        return 0;
    }
    return data[ this->cols * r + c];
}
template <typename T>
bool Mat<T>::setElement(size_t r, size_t c, T value)
{
    if ( r >= this->rows || c >= this->cols)
    {
        cerr << "setElement(): Indices are out of range" << endl;
        return false;
    }

    data[ this->cols * r + c] = value;
    return true;
}

template class Mat<int>; // Explicitly instantiate template Mat
//template Mat and Mat will be instantiate implicitly
int main()
{
    Mat<int> imat(3,4);
    imat.setElement(1, 2, 256);
    Mat<float> fmat(2,3);
    fmat.setElement(1, 2, 3.14159f);
    Mat<double> dmat(2,3);
    dmat.setElement(1, 2, 2.718281828);

    // Mat fmat2(fmat); //error

    // Mat fmat3(2,3);
    // fmat3 = fmat; //error

    cout << imat.getElement(1,2) << endl;
    cout << fmat.getElement(1,2) << endl;
    cout << dmat.getElement(1,2) << endl;
    
    return 0;
}
256
3.14159
2.71828

2- Template Non-Type Parameters

Non-Type Parameters

  • To declare a template
template <parameter-list> declareation
  • The parameters can be

(1) type tamplate parameters
(2) template template parameters
(3) non-type template parameters
integral types, floating-point type, pointer types, Value reference types

vector<int> vec1;
vector<int, 16> vec2;
  • If we want to create a static matrix(no dynamic memory allocation inside)
// Class Template
template<typename T, size_t rows, size_t cols>
class Mat
{
    T data[rows][cols];
  public:
    Mat(){}
    T getElement(size_t r, size_t c);
    bool setElement(size_t r, size_t c, T value);
};
Mat<int> vec1(3, 3);
Mat<int, 3, 3> vec2;

nontypeparam.cpp

#include 
using namespace std;

// Class Template
template<typename T, size_t rows, size_t cols>
class Mat
{
    T data[rows][cols];
  public:
    Mat(){}
     the default copy constructor will copy each element of a static array member
     so we do not 'delete' the copy constructor
     the same with the assignment operator
    // Mat(const Mat&) = delete;
    // Mat& operator=(const Mat&) = delete;
    T getElement(size_t r, size_t c);
    bool setElement(size_t r, size_t c, T value);
};
template<typename T, size_t rows, size_t cols>
T Mat<T, rows, cols>::getElement(size_t r, size_t c)
{
    if ( r >= rows || c >= cols)
    {
        cerr << "getElement(): indices are out of range" << endl;
        return 0;
    }
    return data[r][c];
}
template<typename T, size_t rows, size_t cols>
bool Mat<T, rows, cols>::setElement(size_t r, size_t c, T value)
{
    if ( r >= rows || c >= cols)
    {
        cerr << "setElement(): Indices are out of range" << endl;
        return false;
    }

    data[r][c] = value;
    return true;
}

template class Mat<int, 2, 2>; // Explicitly instantiate template Mat
typedef Mat<int, 2, 2> Mat22i;

//template Mat will be instantiate implicitly

int main()
{
    Mat22i mat;

    mat.setElement(2, 3, 256);
    cout << mat.getElement(2, 3) << endl;

    mat.setElement(1, 1, 256);
    cout << mat.getElement(1, 1) << endl;

    Mat<float, 3, 1> vec;
    vec.setElement(2, 0, 3.14159f);
    cout << vec.getElement(2, 0) << endl;

    Mat<float, 3, 1> vec2(vec);
    cout << vec2.getElement(2, 0) << endl;

    // vec2 = mat; //error

    return 0;
}
setElement(): Indices are out of range
getElement(): indices are out of range
0
256
3.14159
3.14159

Template in OpenCV

【CPP】类模版_第2张图片

【CPP】类模版_第3张图片

  • 模版的继承

【CPP】类模版_第4张图片

将父类的第三个元素锁定为1

【CPP】类模版_第5张图片

3- Class Template Specialization

Class template specialization

  • The class template can be for most types
  • But we want to save memory for type bool (1 byte or 1bit)
template<typename T>
class MyVector
{
    size_t length;
    T * data;
  public:
    MyVector(size_t length): length(length)
    {
        data = new T[length]{};
    }
    ~MyVector()
    {
        delete [] data;
    }
    MyVector(const MyVector&) = delete;
    MyVector& operator=(const MyVector&) = delete;
    T getElement(size_t index);
    bool setElement(size_t index, T value);
};
  • Specialize MyVector for bool
template<>
class MyVector<bool>
{
    size_t length;
    unsigned char * data;
  public:
    MyVector(size_t length): length(length)
    {
        int num_bytes =  (length - 1) / 8 + 1;
        data = new unsigned char[num_bytes]{};
    }
    ~MyVector()
    {
        delete [] data;
    }
    MyVector(const MyVector&) = delete;
    MyVector& operator=(const MyVector&) = delete;
    bool getElement(size_t index);
    bool setElement(size_t index, bool value);
};

Example

specialization.cpp

#include 
using namespace std;

// Class Template
template<typename T>
class MyVector
{
    size_t length;
    T * data;
  public:
    MyVector(size_t length): length(length)
    {
        data = new T[length]{};
    }
    ~MyVector()
    {
        delete [] data;
    }
    MyVector(const MyVector&) = delete;
    MyVector& operator=(const MyVector&) = delete;
    T getElement(size_t index);
    bool setElement(size_t index, T value);
};
template <typename T>
T MyVector<T>::getElement(size_t index)
{
    if (index >= this->length)
    {
        cerr << "getElement(): Indices are out of range" << endl;
        return 0;
    }
    return data[index];
}
template <typename T>
bool MyVector<T>::setElement(size_t index, T value)
{
    if (index >= this->length)
    {
        cerr << "setElement(): Indices are out of range" << endl;
        return false;
    }

    data[ index ] = value;
    return true;
}

template class MyVector<int>; // Explicitly instantiate template Mat

// class specialization
template<>
class MyVector<bool>
{
    size_t length;
    unsigned char * data;
  public:
    MyVector(size_t length): length(length)
    {
        int num_bytes =  (length - 1) / 8 + 1;
        data = new unsigned char[num_bytes]{};
    }
    ~MyVector()
    {
        delete [] data;
    }
    MyVector(const MyVector&) = delete;
    MyVector& operator=(const MyVector&) = delete;
    bool getElement(size_t index);
    bool setElement(size_t index, bool value);
};
bool MyVector<bool>::getElement(size_t index)
{
    if (index >= this->length)
    {
        cerr << "getElement(): Indices are out of range" << endl;
        return 0;
    }
    size_t byte_id = index / 8;
    size_t bit_id = index % 8;
    unsigned char mask = (1 << bit_id);
    return bool(data[byte_id] & mask) ;
}
bool MyVector<bool>::setElement(size_t index, bool value)
{
    if (index >= this->length)
    {
        cerr << "setElement(): Indices are out of range" << endl;
        return false;
    }

    size_t byte_id = index / 8;
    size_t bit_id = index % 8;
    unsigned char mask = (1 << bit_id);

    if (value)
        data[byte_id] |= mask; 
    else 
        data[byte_id] &= ~mask;

    return true;
}

int main()
{
    MyVector<int> vec(16);
    vec.setElement(3, 256);
    cout << vec.getElement(3) << endl;
    
    MyVector<bool> boolvec(17);
    boolvec.setElement(15, false);
    boolvec.setElement(16, true);

    cout << boolvec.getElement(15) << endl;
    cout << boolvec.getElement(16) << endl;
    return 0;
}

256
0
1

4-std Class

std::basic_string

  • Store and manipulate sequences of char-like objects

【CPP】类模版_第6张图片

std::array

  • a container that encapsulates fixed size arrays
template<
  class T,
  std::size_t N
>struct array;
std::array<int, 3>a2 = {1,2,3};  

Some other templates

  • vector
template<
  class T,
  class Allocator = std::allocator<T>
>class vector;
  • list
template<
  class T,
  class Allocator = std::allocator<T>
>class list;
  • set
template<
  class Key,
  class Compare = std::less<Key>,
  class Allocator = std::allocator<Key>
>class set
  • map
template<
  class Key,
  class T,
  class Compare = std::less<Key>,
  class Allocator = std::allocator<std::pair<const Key, T>>
>>class map;
  • stack
template<
  class T,
  class Container = std::deque<T>
>class stack;

你可能感兴趣的:(CPP,c++)