[C++随想录] 模版进阶(下)

简介: [C++随想录] 模版进阶(下)

类模板的特化

函数模版的特化 可以用 函数重载 代替, 难道类模版的特化 也可以用 类的重载 来代替?

打你一耳光哦, 你听过类的重载吗~~

当然不行的啦

类模板的特化分为两种, 全特化 和 偏特化

1. 全特化

全特化, 顾名思义, 是 对类模板中的所有参数都 确定化

template<class T1, class T2>
class Date
{
public:
  Date()
  {
    cout << "Date<class T1, class T2> " << endl;
  }
};
// 类模板的全特化
template<>
class Date<int, double>
{
public:
  Date()
  {
    cout << "Date<int, doule>" << endl;
  }
};
int main()
{
  Date<int, int> d1;
  Date<int, double> d2;
  return 0;
}

运行结果:

Date<class T1, class T2>
Date<int, doule>

妙用:👇👇👇

// 优先级队列, 默认是大堆
namespace muyu
{
  template <class T, class Continer = std::vector<T>, class Compare = Less<T> >
  class priority_queue
  {
  private:
    void AjustUp(int child)
    {
      Compare com;
      int parent = (child - 1) / 2;
      while (child > 0)
      {
        if( com(_con[parent], _con[child]) )
        {
          std::swap(_con[child], _con[parent]);
          // 在内部更新child 和 parent
          child = parent;
          parent = (child - 1) / 2;
        }
        else
        {
          break;
        }
      }
    }
    void AjustDown(int parent)
    {
      Compare com;
      int child = 2 * parent + 1;
      while (child < _con.size())
      {
        // 找到孩子中大的那一个
        if (child + 1 < _con.size() &&  com(_con[child], _con[child + 1]) )
        {
          child++;
        }
        if ( com(_con[parent], _con[child]))
        {
          std::swap(_con[parent], _con[child]);
          parent = child;
          child = parent * 2 + 1;
        }
        else
        {
          break;
        }
      }
    }
  public:
    priority_queue()
    {
    }
    template<class InputIterator>
    priority_queue(InputIterator first, InputIterator last)
    {
      // 一股脑地倒进来
      while (first != last)
      {
        _con.push_back(*first);
        ++first;
      }
      // 建堆
      for (int i = (_con.size() - 1 - 1) / 2; i >= 0; i--)
      {
        AjustDown(i);
      }
    }
    void push(const T& val = T())
    {
      _con.push_back(val);
      AjustUp(_con.size() - 1);
    }
    void pop()
    {
      std::swap(_con[0], _con[_con.size() - 1]);
      _con.pop_back();
      AjustDown(0);
    }
    const T& top() const
    {
      return _con[0];
    }
    bool empty() const
    {
      return _con.size() == 0;
    }
    size_t size() const
    {
      return _con.size();
    }
  private:
    Continer _con;
  };
}
// 日期类
class Date
{
public:
  Date(int year = 1900, int month = 1, int day = 1)
    : _year(year)
    , _month(month)
    , _day(day)
  {}
  bool operator<(const Date& d)const
  {
    return (_year < d._year) ||
      (_year == d._year && _month < d._month) ||
      (_year == d._year && _month == d._month && _day < d._day);
  }
  bool operator>(const Date& d)const
  {
    return (_year > d._year) ||
      (_year == d._year && _month > d._month) ||
      (_year == d._year && _month == d._month && _day > d._day);
  }
  friend ostream& operator<<(ostream& _cout, const Date& d);
private:
  int _year;
  int _month;
  int _day;
};
// 日期类重载留插入
ostream& operator<<(ostream& _cout, const Date& d)
{
  _cout << d._year << "-" << d._month << "-" << d._day;
  return _cout;
}
// 仿函数
template <class T>
class Less
{
public:
  bool operator()(const T& x, const T& y)
  {
    return x < y;
  }
};
// 全特化
template <>
class Less<Date*>
{
public:
  bool operator()(const Date* x, const Date* y)
  {
    return *x < *y;
  }
};
void test()
{
  muyu::priority_queue<Date*> pq;
  pq.push(new Date(2023, 9, 27));
  pq.push(new Date(2023, 9, 28));
  pq.push(new Date(2023, 9, 29));
  pq.push(new Date(2023, 9, 1));
  while (!pq.empty())
  {
    cout << *pq.top() << " ";
    pq.pop();
  }
  cout << endl;
}
int main()
{
  test();
  return 0;
}

运行结果:

2023-9-29 2023-9-28 2023-9-27 2023-9-1

这样的好处:


传参类型如果是 T, 那么就按照 T 来进行比较; 如果传参类型是 Date*, 那么就按照 Date 来进行比较

其实没有 模版的特化, 我们无法同时写出 T 和 Date* 的一个仿函数.

2.偏特化

偏特化又有两种形式: 部分特化 和 对参数做进一步限制


部分特化

template<class T1, class T2>
class Date
{
public:
  Date()
  {
    cout << "Date<class T1, class T2> " << endl;
  }
};
// 类模板的偏特化
template<class T1>
class Date<T1, double>
{
public:
  Date()
  {
    cout << "Date<T1, double>" << endl;
  }
};
// 类模板的偏特化
template<class T1>
class Date<T1, int&>
{
public:
  Date()
  {
    cout << "Date<T1, int&>" << endl;
  }
};
int main()
{
  Date<int, int> d1;
  Date<int, double> d2;
  Date<int, int&> d3;
  return 0;
}

运行结果:

Date<class T1, class T2>
Date<T1, double>
Date<T1, int&>
  1. 对参数做进一步限制
template<class T1, class T2>
class Date
{
public:
  Date()
  {
    cout << "Date<class T1, class T2> " << endl;
  }
};
// 类模板的偏特化
template<class T1, class T2>
class Date<T1*, T2*>
{
public:
  Date()
  {
    cout << "Date<T1*, T2*>" << endl;
  }
};
// 类模板的偏特化
template<class T1, class T2>
class Date<T1&, T2&>
{
public:
  Date()
  {
    cout << "Date<T1&, T2&>" << endl;
  }
};
int main()
{
  Date<int, int> d1;
  Date<int*, double*> d2;
  Date<int& , int&> d3;
  return 0;
}

运行结果:

Date<class T1, class T2>
Date<T1*, T2*>
Date<T1&, T2&>

那么, 我们可以把所有 有关迭代器的比较 特化成 迭代器指向内容的比较, 从而达到我们比较的目的

// 优先级队列, 默认是大堆
namespace muyu
{
  template <class T, class Continer = std::vector<T>, class Compare = Less<T> >
  class priority_queue
  {
  private:
    void AjustUp(int child)
    {
      Compare com;
      int parent = (child - 1) / 2;
      while (child > 0)
      {
        if( com(_con[parent], _con[child]) )
        {
          std::swap(_con[child], _con[parent]);
          // 在内部更新child 和 parent
          child = parent;
          parent = (child - 1) / 2;
        }
        else
        {
          break;
        }
      }
    }
    void AjustDown(int parent)
    {
      Compare com;
      int child = 2 * parent + 1;
      while (child < _con.size())
      {
        // 找到孩子中大的那一个
        if (child + 1 < _con.size() &&  com(_con[child], _con[child + 1]) )
        {
          child++;
        }
        if ( com(_con[parent], _con[child]))
        {
          std::swap(_con[parent], _con[child]);
          parent = child;
          child = parent * 2 + 1;
        }
        else
        {
          break;
        }
      }
    }
  public:
    priority_queue()
    {
    }
    template<class InputIterator>
    priority_queue(InputIterator first, InputIterator last)
    {
      // 一股脑地倒进来
      while (first != last)
      {
        _con.push_back(*first);
        ++first;
      }
      // 建堆
      for (int i = (_con.size() - 1 - 1) / 2; i >= 0; i--)
      {
        AjustDown(i);
      }
    }
    void push(const T& val = T())
    {
      _con.push_back(val);
      AjustUp(_con.size() - 1);
    }
    void pop()
    {
      std::swap(_con[0], _con[_con.size() - 1]);
      _con.pop_back();
      AjustDown(0);
    }
    const T& top() const
    {
      return _con[0];
    }
    bool empty() const
    {
      return _con.size() == 0;
    }
    size_t size() const
    {
      return _con.size();
    }
  private:
    Continer _con;
  };
}
// 日期类
class Date
{
public:
  Date(int year = 1900, int month = 1, int day = 1)
    : _year(year)
    , _month(month)
    , _day(day)
  {}
  bool operator<(const Date& d)const
  {
    return (_year < d._year) ||
      (_year == d._year && _month < d._month) ||
      (_year == d._year && _month == d._month && _day < d._day);
  }
  bool operator>(const Date& d)const
  {
    return (_year > d._year) ||
      (_year == d._year && _month > d._month) ||
      (_year == d._year && _month == d._month && _day > d._day);
  }
  friend ostream& operator<<(ostream& _cout, const Date& d);
private:
  int _year;
  int _month;
  int _day;
};
// 日期类重载留插入
ostream& operator<<(ostream& _cout, const Date& d)
{
  _cout << d._year << "-" << d._month << "-" << d._day;
  return _cout;
}
// 仿函数
template <class T>
class Less
{
public:
  bool operator()(const T& x, const T& y)
  {
    return x < y;
  }
};
// 偏特化
template <class T>
class Less<T*>
{
public:
  bool operator()(const T* x, const T* y)
  {
    return *x < *y;
  }
};
void test()
{
  muyu::priority_queue<Date*> pq;
  pq.push(new Date(2023, 9, 27));
  pq.push(new Date(2023, 9, 28));
  pq.push(new Date(2023, 9, 29));
  pq.push(new Date(2023, 9, 1));
  while (!pq.empty())
  {
    cout << *pq.top() << " ";
    pq.pop();
  }
  cout << endl;
}
int main()
{
  test();
  return 0;
}
模版的特化总结:
模版的特化离不开原模版, 不能独立存在
特化是做特殊化处理, 具体情况具体使用


相关文章
|
2月前
|
编译器 C++
C++进阶之路:何为运算符重载、赋值运算符重载与前后置++重载(类与对象_中篇)
C++进阶之路:何为运算符重载、赋值运算符重载与前后置++重载(类与对象_中篇)
33 1
|
2月前
|
安全 算法 C语言
【C++进阶】深入STL之string:掌握高效字符串处理的关键
【C++进阶】深入STL之string:掌握高效字符串处理的关键
32 1
【C++进阶】深入STL之string:掌握高效字符串处理的关键
|
2月前
|
编译器 C++
C++模板进阶
C++模板进阶
16 1
|
2月前
|
存储 算法 程序员
【C++进阶】深入STL之 栈与队列:数据结构探索之旅
【C++进阶】深入STL之 栈与队列:数据结构探索之旅
28 4
|
2月前
|
算法 安全 编译器
【C++进阶】模板进阶与仿函数:C++编程中的泛型与函数式编程思想
【C++进阶】模板进阶与仿函数:C++编程中的泛型与函数式编程思想
34 1
|
2月前
|
存储 算法 程序员
【C++进阶】深入STL之vector:构建高效C++程序的基石
【C++进阶】深入STL之vector:构建高效C++程序的基石
29 1
|
2月前
|
编译器 C++
【C++进阶】深入STL之string:模拟实现走进C++字符串的世界
【C++进阶】深入STL之string:模拟实现走进C++字符串的世界
28 1
|
2月前
|
C++
C++中函数模版与类模版
C++中函数模版与类模版
41 4
|
2月前
|
存储 缓存 编译器
【C++进阶】深入STL之list:模拟实现深入理解List与迭代器
【C++进阶】深入STL之list:模拟实现深入理解List与迭代器
19 0
|
2月前
|
C++ 容器
【C++进阶】深入STL之list:高效双向链表的使用技巧
【C++进阶】深入STL之list:高效双向链表的使用技巧
29 0