【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"
cpp 复制代码
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, double)
template double sum<double> (double, double);
// instantiates sum<char> (char, char), template argument deduced
template char sum<> (char, char);
// instantiates sum<int>(int, int), template argument deduced
template int sum(int, int);

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

  • Implicit instantiation occurs when a function template is not explicitly instantiated
cpp 复制代码
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, int)
cout << "product = " << product<int>(2.2f, 3.0f) << endl;
// Implicitly instantiates product<float>(float, float)
cout << "product = " << product(2.2f, 3.0f) << endl;

Different Classes for Different Type Matrices

  • Matrix with int elements, Matrix with float elements

matchless.cpp

cpp 复制代码
#include <iostream>
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;
}
bash 复制代码
256
3.14159

Class Templates

  • A class template defines a family of classes

mat template.cpp

cpp 复制代码
#include <iostream>
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<int>
//template Mat<float> and Mat<double> 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<float> fmat2(fmat); //error

    // Mat<float> 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;
}
bash 复制代码
256
3.14159
2.71828

2- Template Non-Type Parameters

Non-Type Parameters

  • To declare a template
cpp 复制代码
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

cpp 复制代码
vector<int> vec1;
vector<int, 16> vec2;
  • If we want to create a static matrix(no dynamic memory allocation inside)
cpp 复制代码
// 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);
};
cpp 复制代码
Mat<int> vec1(3, 3);
Mat<int, 3, 3> vec2;

nontypeparam.cpp

cpp 复制代码
#include <iostream>
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<int, 2, 2>
typedef Mat<int, 2, 2> Mat22i;

//template Mat<float, 3, 1> 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;
}
bash 复制代码
setElement(): Indices are out of range
getElement(): indices are out of range
0
256
3.14159
3.14159

Template in OpenCV

  • 模版的继承

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

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)
cpp 复制代码
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
cpp 复制代码
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

cpp 复制代码
#include <iostream>
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<int>

// 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;
}
bash 复制代码
256
0
1

4-std Class

std::basic_string

  • Store and manipulate sequences of char-like objects

std::array

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

Some other templates

  • vector
cpp 复制代码
template<
  class T,
  class Allocator = std::allocator<T>
>class vector;
  • list
cpp 复制代码
template<
  class T,
  class Allocator = std::allocator<T>
>class list;
  • set
cpp 复制代码
template<
  class Key,
  class Compare = std::less<Key>,
  class Allocator = std::allocator<Key>
>class set
  • map
cpp 复制代码
template<
  class Key,
  class T,
  class Compare = std::less<Key>,
  class Allocator = std::allocator<std::pair<const Key, T>>
>>class map;
  • stack
cpp 复制代码
template<
  class T,
  class Container = std::deque<T>
>class stack;
相关推荐
怀澈12219 分钟前
高性能服务器模型之Reactor(单线程版本)
linux·服务器·网络·c++
chnming198742 分钟前
STL关联式容器之set
开发语言·c++
威桑1 小时前
MinGW 与 MSVC 的区别与联系及相关特性分析
c++·mingw·msvc
熬夜学编程的小王1 小时前
【C++篇】深度解析 C++ List 容器:底层设计与实现揭秘
开发语言·数据结构·c++·stl·list
yigan_Eins1 小时前
【数论】莫比乌斯函数及其反演
c++·经验分享·算法
Mr.131 小时前
什么是 C++ 中的初始化列表?它的作用是什么?初始化列表和在构造函数体内赋值有什么区别?
开发语言·c++
阿史大杯茶1 小时前
AtCoder Beginner Contest 381(ABCDEF 题)视频讲解
数据结构·c++·算法
C++忠实粉丝1 小时前
计算机网络socket编程(3)_UDP网络编程实现简单聊天室
linux·网络·c++·网络协议·计算机网络·udp
我们的五年2 小时前
【Linux课程学习】:进程描述---PCB(Process Control Block)
linux·运维·c++
程序猿阿伟2 小时前
《C++ 实现区块链:区块时间戳的存储与验证机制解析》
开发语言·c++·区块链