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

时间:2014-08-20 14:37:53

标签: c++ templates

我是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()函数?

2 个答案:

答案 0 :(得分:3)

这一行:

// 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函数。

编辑:排序可能会像这样:

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`
}

答案 1 :(得分:1)

operator()是函数调用运算符。此功能允许您将对象视为函数。

  

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

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

编译器不会“了解这一点”。它必须这样做才能符合这个标准。

<强>更新
有两个版本的std::sort,一个带有两个参数来指定要排序的范围,另一个带有一个额外的参数来指定比较函数(或仿函数)。

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

三个参数版本需要调用函数(或函数对象)来代替小于。你为什么要这样做?原因很多。只是一对:也许这个类的作者没有为类定义小于运算符,并且你不能改变那个类。或者您可能希望根据上下文更改小于的含义。有时您希望按创建日期对集合进行排序,其他时间按上次更改日期排序,其他时间按名称排序。