C++ 学习系列 -- 模板 template

一  C++ 模板介绍?

  C++ 为什么引入模板?

      我的理解是:

C++ 引入模板的概念,是为了复用重复的代码,当某些代码除了操作的数据类型不同以外,其他逻辑全都相同,此时就适合采用模板的方式。

定义模板类或者模板函数时,只是定义了一个代码的架子,使用时需要配合上实际的数据类型,数据类型可以是基本数据类型也可以是用户自定义的类型。

官方一点的说法:

所谓模板,实际上是建立一个通用函数或类,其类内部的类型和函数的形参类型不具体指定,用一个虚拟的类型来代表。这种通用的方式称为模板。

模板是泛型编程的基础,泛型编程即以一种独立于任何特定类型的方式编写代码。

这种模板的设计在许多编程语言中是由类似的,比如 Java 、Scala 中都有模板的概念。

二  class template 类模板

类模板例子:

// complex.h
template
class Complex
{
public:
    Complex(T re = 0, T im = 0):m_re(re), m_im(im)
    {

    }

    Complex& operator+=(const Complex& other);

    T real() const
    {
        return m_re;
    }

    T imag() const
    {
        return m_im;
    }


private:
    T m_re;
    T m_im;
};


template
Complex& Complex::operator+=(const Complex& other)
{
    this->m_re += other.m_re; // 任意一个类都是自己的 friend class,所以可以使用 private 成员变量
    this->m_im += other.m_im;
    return *this;
}

// main.cpp
#include"complex.h"

int main()
{
    Complex c1(1, 2);
    Complex    c2(1.1, 2.2);
    Complex  c3(1.1, 2.2);

    return 0;
}

上面是一个复数 Complex模板类的简单实现。

三  function template 函数模板

// complex.h
template
class Complex
{
public:
    Complex(T re = 0, T im = 0):m_re(re), m_im(im)
    {

    }

    bool operator<(const Complex& other) const
    {
        if(this->m_re < other.m_re)
        {
            return true;
        }
        else if(this->m_re > other.m_re)
        {
            return false;
        }
        else
        {
            if(this->m_im < other.m_im)
            {
                return true;
            }
            else
            {
                return false;
            }
        }
    }

    T real() const
    {
        return m_re;
    }

    T imag() const
    {
        return m_im;
    }


private:
    T m_re;
    T m_im;
};

// main.cpp
#include 
#include"complex.h"

// 模板函数
template
const T& myMin(const T& a, const T& b)
{
    return a < b ? a : b;
}

int main()
{
      int a1 = 11;
      int b1 = 22;
      std::cout << myMin(a1, b1) << std::endl;

      double a2 = 1.1;
      double b2 = 2.2;
      std::cout << myMin(a2, b2) << std::endl;
      
      Complex c11(11, 2);
      Complex c12(1, 22);

      auto cc = myMin(c11, c12);
      std::cout << cc.real() << ", " << cc.imag() << std::endl;
  
      return 0;
}


       以上代码定义了一个模板函数 myMin ;一个模板类 Complex,自定义了一个 operator< 成员函数。

      从代码中我们发现一个问题,模板类要用尖括号指明实际的元素类型,而模板函数并不需要尖括号指明实际的元素类型。这是因为在 C++ 中,模板函数在调用时,可以通过传入的实参推断出形参的类型,因而不需要指明实际的元素类型。

      模板函数 myMin 传入的类型需要有比较的能力,c++ 基本类型天然就具有比较的能力,而用户自定义类型需要实现 operator< 成员函数,才能在编译到 < 那行代码时能够通过,若是自定义类型没有实现 operator< 成员函数时,编译会出现错误。

四  member template 成员模板

成员模板也是一种函数模板,只不过针对的是构造函数的模板。

// base.h
class Base2
{

};

class Derive2:public Base2
{

};

class Base3
{
    
};

class Derive3:public Base3
{
    
};

// my_pair.h
template
class MyPair
{
public:
    typedef T1 firstArgumentType;
    typedef T1 secondArgumentType;

    MyPair():first(T1()), second(T2())
    {
    }

    MyPair(const T1& arg1, const T2& arg2):first(arg1), second(arg2)
    {
    }

    // 成员模板
    template
    MyPair(const MyPair& other):first(other.first),second(other.second)
    {
    }
public:
    T1 first;
    T2 second;
};

// main.cpp
#include"my_pair.h"
#include"base.h"

int main()
{
    MyPair pair1;
    MyPair pair2;

    MyPair pair3(pair2);

   return 0;
}

五  模板特化(specialization)与偏特化(partial specialization)

1. 模板特化 (specialization)

      模板特化指得是将模板类或者模板函数特化到某些特定的指定类型,使得在编译器编译时,实际编译执行的代码是特化后的版本。

 

// my_hash.h
#include
#include

template 
struct my_hash
{
    T operator()(T x)
    {
        std::cout << "template  struct my_hash" << std::endl;
        return x;
    }
};

// 以下为三个特化版本
template<>
struct my_hash
{
    int operator()(int x)
    {
        std::cout << "template <> struct my_hash" << std::endl;
        return x;
    }
};

template<>
struct my_hash
{
    char operator()(char x)
    {
        std::cout << "template <> struct my_hash" << std::endl;
        return x;
    }
};

template<>
struct my_hash
{
    long operator()(long x)
    {
        std::cout << "template <> struct my_hash" << std::endl;
        return x;
    }
};
// main.cpp

#include"my_hash.h"

int main()
{
    std::cout << my_hash()("abcd") << std::endl;

    std::cout << my_hash()('a') << std::endl;
    std::cout << my_hash()(66) << std::endl;
    std::cout << my_hash()(6666) << std::endl;

    return 0;
}

 输出:

C++ 学习系列 -- 模板 template_第1张图片

2. 模板偏特化(partial specialization)

2.1  个数偏特化

      模板的个数变化时的特化版本

// my_vector.h
#include

template
class my_vector
{
public:
    my_vector()
    {
        std::cout << "template class my_vector" << std::endl;
    }
};

template
class my_vector
{
public:
    my_vector()
    {
        std::cout << "template class my_vector" << std::endl;
    }
};

// main.cpp
#include"my_vector.h"

int main()
{
   my_vector>  vec1;
   my_vector>  vec2;

   return 0;
}

输出:

2.2 范围偏特化

      通过特化模板类型的指针来实现指针的特化

// e.h
#include

template
class E
{
public:
    E()
    {
        std::cout << "template class E" << std::endl;
    }
};

template
class E
{
public:
    E()
    {
        std::cout << "template class E" << std::endl;
    }
};

// main.cpp
#include"e.h"

int main()
{
    E e1;
    E e2;
    
    return 0;
}

输出:

六  模板模板参数(template template parameter)

模板模板参数其实就是模板的其中参数又是另外一个模板参数,示例代码如下:

XCLS 类 的第一个模板参数是 T ,第二个模板参数是一个模板类 Container,我们可以定义一个 XX 模板类来组合使用 XCLS ,将 XX 传入即可;

也可以使用容器类 list  传入,但是如果直接传入编译是会出错的,比如下面

   XCLS xcls3; 编译不过

  编译不过的原因是,std::list 实际上是两个模板参数,编译器检查时发现少给了一个模板参数 _Alloc ,所以编译不过。 

template >
    class list;

可以通过如下定义 Lst 来将模板类 list 的模板参数限定为 一个

template
using Lst = std::list>;
// xcls.h
#include

template class Container>
class XCLS
{
public:
    XCLS()
    {
        std::cout << "template class Container> class XCLS" << std::endl;
    }
private:
    Container c;
};

template
class XX
{
public:
    XX()
    {
        std::cout << "template class XX" << std::endl;
    }
};

// main.cpp
#include"xcls.h"

int main()
{  
   // 模板模板的参数使用
   XCLS xcls1;
   XCLS xcls2;
   // XCLS xcls3; 编译不过

   return 0;
}

输出:

你可能感兴趣的:(c++,学习,开发语言)