解释这个c++模板是如何工作的

Explanation how this C++ template is working?

本文关键字:何工作 工作 c++ 解释      更新时间:2023-10-16

我是c++的新手,在我努力学习这门语言的过程中,我写了一个模板,并且工作得很好,但是我对整个事情是如何工作的感到困惑!

我的模板包含一个结构体,该结构体有一个operator()成员函数,用作std::sort函数的谓词。模板有一个实参,它是指向类成员的指针,这样我就可以传递不同的类成员作为模板的实参。

代码:

// template definition
template<typename T, string T::*mp>
struct LessThan{
    inline bool operator()(const T& c1, const T& c2){
        return (c1.*mp < c2.*mp);
     }
 };
// class definition
class Person{
public:
  ...
  // fields I'll for sorting
  string first_name;
  string last_name;
};
// Somewhere in my code, create persons and fill the vector of persons
vector<Person>persons;
p1 = Person('John','Gath');
persons.push_back(p1);
...
persons.push_back(p20);
//now I want to sort my vector of persons by either frist_name or last_name
// initialize the template
LessThan<Person, &Person::first_name>lt_fname;
// my puzzle !!
std::sort(persons.begin(), persons.end(), lt_fname); //<--NOTICE, NO () when passing lt_fname
LessThan<Person, &Person::last_name>lt_lname;
std::sort(persons.begin(), persons.end(), lt_lname);  // no () for lt_lname

代码可以很好地编译和运行!

令我困惑的是,我以前的版本的谓词LessThan没有使用模板,但当它传递给sort时,必须使用()括号!

编译器如何知道如何调用operator()函数?

保罗

这一行:

// initialize the template
LessThan<Person, &Person::first_name> lt_fname;

不初始化模板,而是创建一个实例:lt_fname。该实例被传递给std::sort。你也可以这样做:

std::sort(persons.begin(), persons.end(), LessThan<Person, &Person::first_name>());

这次将动态实例化模板,向sort函数传递一个临时变量。

EDIT: Sort可能这样工作:

template< class RandomIt, class Compare >
void sort( RandomIt first, RandomIt last, Compare comp )
{
  // assuming RandomIt a, b are two valid items, comp is called:
  auto aIsLess = comp(a, b); // it uses the operator() of `Compare`
}

说明operator()为函数调用操作符。这个功能允许你把一个对象当作一个函数来对待。

编译器如何知道如何调用operator()函数?

编译器知道您的lt_lname是一个对象而不是一个函数名。即使您确实有一个名为lt_name的函数,您对lt_name的声明也隐藏了该名称。唯一的其他选择是使用对象的函数调用操作符。

编译器不会"知道这个"。它必须这样做才能符合这个标准。


std::sort有两个版本,一个带两个实参,指定要排序的范围,另一个带一个额外的实参,指定比较函数(或functor)。

sort的双参数版本使用小于操作符来比较对象。由于operator<可以重载,因此为类定义operator<提供了对该类实例集合进行排序的一种方法。

三个参数的版本接受一个要调用的函数(或函数对象)来代替小于。你为什么要这么做?原因有很多。只有几个问题:可能有问题的类的作者没有为该类定义小于操作符,并且您无法更改该类。或者你想根据上下文改变less than的意思。有时您希望按创建日期排序,有时按最后更改日期排序,有时按名称排序。