我知道函子是一个函数对象,是结构定义中()运算符的重载。 同样,在算法中使用函子似乎很简单,只需调用此例程即可。
但是我无法理解比较器。为什么在模板参数中首先使用它们。
有人可以用map等STL中的模板实现来详细说明两者之间的区别吗?
编辑:
我正在寻找以下内容的答案
答案 0 :(得分:7)
您对 functor 的定义是正确的-尽管该单词在标准语言本身中并不存在,所以人们的使用方式可能略有不同。
标准库中有许多函数或类模板,它们会带有某种可调用的对象-这可能是函子或指向函数的指针(实际上只是一个函数,而不是带有operator()
的类)。
比较器是满足Compare requirements的类型的对象-即,可以用两件事调用并返回bool
的函数或类对象,并且特别满足一些称为“ 严格弱排序”的数学要求。
从本质上讲,这意味着比较器是一个函子,您可以用来按正确的顺序放置一些数字。 (数字,std::string
,Customer
,无论其他什么,只要有一种合理的,一致的方式将它们排序即可。)
因此使用函子的一个简单例子可能是:
void print(int i)
{
std::cout << i << '\n';
}
// ...
std::for_each(std::begin(some_ints), std::end(some_ints), print);
但是,如果您想按其客户ID对某些Customer
进行排序,则可以这样操作:
struct Customer {
std::string surname;
std::string given_name;
std::uint64_t customer_id;
};
bool compareById(Customer const& first, Customer const& second)
// this function meets the Compare requirements
{
return first.customer_id < second.customer_id;
}
// ...
std::sort(std::begin(customers), std::end(customers), compareById);
假设您稍后要按客户的名称对客户进行排序-首先是姓,然后如果姓相同,则给定名称,您可以提供其他功能:
bool compareByName(Customer const& first, Customer const& second)
{
// std::tie is an idiomatic way to correctly sort on multiple values
return std::tie(first.surname, first.given_name)
< std::tie(second.surname, second.given_name);
}
std::sort(std::begin(customers), std::end(customers), compareByName);
我正在努力创造一个示例,其中您需要将比较器作为一个类,但让我们假设您想将其所做的所有比较打印到日志文件中;那么该文件将需要由对象存储状态:
struct LoggingCustomerComparator {
std::ostream& logFile;
LoggingCustomerComparator(std::ostream& logFile) : logFile(logFile) {}
bool operator()(Customer const& first, Customer const& second)
{
// assume we have an operator<< for Customer
logFile << "Comparing: " << first << " and " << second << '\n';
return first.customer_id < second.customer_id;
}
};
// ...
using OrderId = std::uint64_t;
using LCC = LoggingCustomerComparator;
std::map<Customer, OrderId, LCC> latestCustomerOrder(LCC(std::clog));
// ^^^ type ^^^ construct object with the log file we want
上面的示例说明了如何使用带有函子或比较器的函数模板,但是如果您想编写这样的函数模板怎么办?让我们以标准库算法的样式实现Bogosort:
template <typename RandIt, typename Comp>
void bogosort(RandIt first, RandIt last, Comp comp)
{
std::random_device rd;
std::mt19937 g(rd());
while ( !std::is_sorted(first, last, comp) ) {
std::shuffle(first, last, g);
}
}
了解如何see here实施is_sorted
。
答案 1 :(得分:0)
在评论部分,用户指出了正确的答案,然后回首我只是在扩展它
基本上,比较器是类型而不是对象,因此传递类型对模板类更有意义,因为其元编程(即编译器正在编写自己的代码),因此使类自行创建内部对象更有意义而不是依靠用户来提供。