C++函数模板的问题

问题遇到的现象和发生背景

刚学习C++,对它的理解还停留在数据成员和成员函数,这里遇到的函数模板问题,解决不了

问题相关代码,请勿粘贴截图
The function template min_elem() finds the smallest element in the range [first, last) and returns the iterator to the smallest element. The way how smallest is understood can be customized.

 

#include <functional>
#include <iostream>
#include <iterator>
#include <string>
#include <list>
#include <vector>

template<class ForwardIt, class Compare>
ForwardIt min_elem(ForwardIt first, ForwardIt last, 
 comp)
{
  if (first == last)
    return 
;

  ForwardIt smallest = first++;
  for (; 
; ++first) {
    if (comp(*first, *smallest)) {
      smallest = first;
    }
  }
  return 
;
}

template<class ForwardIt>
ForwardIt min_elem(ForwardIt first, ForwardIt last)
{
  return min_elem(first, last, std::less<
 std::iterator_traits<ForwardIt>::value_type>());
}

struct Student {
  int id;
  std::string name;
  bool 
(const Student& s2) const {
    return id < s2.id;
  }
};

std::ostream& operator<<(std::ostream& out, const Student& s)
{
  out << s.name << s.id;
  return out;
}

int main()
{
  std::vector<int> v = { 3, 1, 4, 2, 5, 9 };
  std::cout << "min element is: " << *min_elem(std::begin(v), std::end(v)) << std::endl;
  
  std::list<double> l = { 3.1, 1.2, 4.3, 2.4, 5.5, 9.7 };
  std::cout << "min element is: " << *min_elem(std::begin(l), std::end(l), std::greater<double>()) << std::endl;
  
  Student s[] = { {30, "Curry"}, {23, "Lebron"}, {35, "Durant"} };
  std::cout << "min element is: " << *min_elem(std::begin(s), std::end(s)) << std::endl;
}

运行结果及报错内容

img

我的解答思路和尝试过的方法

还不太明白函数模板的原理

我想要达到的结果

希望给出题目解答的同时,给出一些思路上的指点


// The function template min_elem() finds the smallest element in the range [first, last) and returns the iterator to the smallest element. The way how smallest is understood can be customized.
 
 
 
#include <functional>
#include <iostream>
#include <iterator>
#include <string>
#include <list>
#include <vector>
 
template<class ForwardIt, class Compare>
ForwardIt min_elem(ForwardIt first, ForwardIt last, 
Compare // 比较类实例
comp)
{
  if (first == last)
    return first; // 返回第一个.
 
  ForwardIt smallest = first++;
  for (; first != last // 当前不是迭代器末尾.
    ; ++first) {
    if (comp(*first, *smallest)) {
      smallest = first;
    }
  }
  return smallest // smallest保存着最小值。
;
}
 
template<class ForwardIt>
ForwardIt min_elem(ForwardIt first, ForwardIt last)
{
  return min_elem(first, last, std::less< typename // 去除语义二义性。
 std::iterator_traits<ForwardIt>::value_type>());
}
 
struct Student {
  int id;
  std::string name;
  bool operator< //运算符重载
(const Student& s2) const {
    return id < s2.id;
  }
};
 
std::ostream& operator<<(std::ostream& out, const Student& s)
{
  out << s.name << s.id;
  return out;
}
 
int main()
{
  std::vector<int> v = { 3, 1, 4, 2, 5, 9 };
  std::cout << "min element is: " << *min_elem(std::begin(v), std::end(v)) << std::endl;
  
  std::list<double> l = { 3.1, 1.2, 4.3, 2.4, 5.5, 9.7 };
  std::cout << "min element is: " << *min_elem(std::begin(l), std::end(l), std::greater<double>()) << std::endl;
  
  Student s[] = { {30, "Curry"}, {23, "Lebron"}, {35, "Durant"} };
  std::cout << "min element is: " << *min_elem(std::begin(s), std::end(s)) << std::endl;
}
 

//The function template min_elem() finds the smallest element in the range[first, last) and returns the iterator to the smallest element.The way how smallest is understood can be customized.



#include <functional>
#include <iostream>
#include <iterator>
#include <string>
#include <list>
#include <vector>

template<class ForwardIt, class Compare>
ForwardIt min_elem(ForwardIt first, ForwardIt last,Compare comp)    //comp是一个比较函数
{
    //这里是只有一个元素的情况
    if (first == last)
        return first;


    //这里就是一个循环找最小的元素,smallest保存最小元素的迭代器
    ForwardIt smallest = first++;
    //终止条件就是头迭代器到尾迭代器,说明整个走完了
    for (;first!=last; ++first) {
        if (comp(*first, *smallest)) {
            smallest = first;
        }
    }
    //返回迭代器
    return smallest;
}

template<class ForwardIt>
ForwardIt min_elem(ForwardIt first, ForwardIt last)
{
                                   //默认的一个从小到大的比较函数,传入的值是数据类型
    return min_elem(first, last, std::less<std::iterator_traits<ForwardIt>::value_type>()); 
}

struct Student {
    int id;
    std::string name;
    //重载<运算符
    bool operator <(const Student& s2) const {
        return id < s2.id;
    }
};

std::ostream& operator<<(std::ostream& out, const Student& s)
{
    out << s.name << s.id;
    return out;
}

int main()
{
    std::vector<int> v = { 3, 1, 4, 2, 5, 9 };
    std::cout << "min element is: " << *min_elem(std::begin(v), std::end(v)) << std::endl;

    std::list<double> l = { 3.1, 1.2, 4.3, 2.4, 5.5, 9.7 };
    std::cout << "min element is: " << *min_elem(std::begin(l), std::end(l), std::greater<double>()) << std::endl;

    Student s[] = { {30, "Curry"}, {23, "Lebron"}, {35, "Durant"} };
    std::cout << "min element is: " << *min_elem(std::begin(s), std::end(s)) << std::endl;
}

img

首先 注意区分两个概念:
类模版 和模版类
函数模版 和 模版函数
类/函数模版 是家族 ,模版类/函数 是家族的一个成员。

C++中类模板的声明格式为template<模板形参表声明><类声明>,并且类模板的成员函数都是模板函数

什么是非类型模版參数:就是传来的参数 可以当作实參使用。
注意:

浮点数、类对象以及字符串是不允许作为非类型模板参数的。
非类型的模板参数必须在编译期就能确认结果。
模板的特性
首先来看一个例子:

template int Func1() { return n; }

int Func2(int n) { return n; }

你能看出这两个函数的区别在哪里吗?

它们的区别就在于,Func1的参数是编译期指定,如Func1<0>() ;而Func2的参数则是运行期指定。

一:分离编译
简单说什么是分离编译: 类似于项目中 编译生成 不同的链接文件的意思。

特性一:: 这正体现了模板的特性或者说是它的技术核心,就是编译期的动态机制,这种机制使程序在运行期具有更大的效率优势。

到此你是不是对本文开头那段代码有了更深入的理解了呢?

二 特化
特划分为 : 全特化 、半特化
半特化可以只是简单的特化 ,也可以说对类型的限制。 外部传T 等,内部用 *T & T 等。

特性 二: 如果一个模板没有被特化,那么编译器根本不会去理会它,也就是说模板内的代码被隐藏了

函数模板与类模板
函数模版
------后边跟着一个具体的函数
1
这是一个函数模板:template Func(T param) {}

函数模板的模板参数是隐式的,编译器会自动根据传入值的类型来确定模板参数的类型。因此函数模板的模板参数不能有默认值。

这是一个类模板:template class MyClass {};

类模板
------后边跟着一个具体的类
1
类模版的模板参数是显式的,使用一个模板类时必须指明其模板参数,因此类模板的模板参数可以有默认值。

我们还可以做更多的事情,比如MyClass可以派生自T(XTP界面库就是这么做的),在MyClass内部可以使用关于T的enum、typedef等等。这些将在下文一一谈到。

(我在这里提出一个建议,创建一个类模板,请记得第一件事就是对模板参数进行typedef定义。)

模板的部分特化与应用
模板最有价值的地方就是它的部分特化,也是应用最广泛的特性。

所谓“部分特化”也就是说,一个模板有多个参数,但我们只对其中一部分参数进行特化,或者是只针对常量模板参数的某种情况进行特化。

编译期ASSERT
这是对bool型模板参数部分特化的一个例子。最简单的实现:

template struct CompileTimeAssert;

template<> struct CompileTimeAssert {};

当我们将一个表达式作为模板参数,而这个表达式的值为false时,编译器就找不到合适的实现,便会报错了

事实是编译期可用的表达式或函数(如sizeof)数量上并不多。

模板总结 【优点】
【优点】

模板复用了代码,节省资源,更快的迭代开发,C++的标准模板库(STL)因此而产生
增强了代码的灵活性
【缺陷】
3. 模板会导致代码膨胀问题,也会导致编译时间变长
4. 出现模板编译错误时,错误信息非常凌乱,不易定位错误