我有两个与函数对象和函数指针相关的问题,
问题:1
当我读到STL的不同用法sort
算法时,我看到第三个参数可以是一个函数对象,下面是一个例子
class State {
public:
//...
int population() const;
float aveTempF() const;
//...
};
struct PopLess : public std::binary_function<State,State,bool> {
bool operator ()( const State &a, const State &b ) const
{ return popLess( a, b ); }
};
sort( union, union+50, PopLess() );
现在,声明sort(union, union+50,PopLess())
如何运作?必须将PopLess()
解析为PopLess tempObject.operator()
之类的内容,这与在临时对象上执行operator ()
函数相同。我将此视为,将重载操作的返回值,即bool
(如我的示例中)传递给sort
算法。
那么,在这种情况下,sort函数如何解析第三个参数?
问题:2
我们是否使用函数对象与函数指针相比具有任何特定优势?如果我们使用下面的函数指针,它会导致任何不利吗?
inline bool popLess( const State &a, const State &b )
{ return a.population() < b.population(); }
std::sort( union, union+50, popLess ); // sort by population
PS:以上参考文献(包括示例)均来自“Stephen C. Dewhurst”的书“C ++ Common Knowledge:Essential Intermediate Programming”。 我无法解码主题内容,因此已发布求助。
提前感谢您的帮助。
答案 0 :(得分:8)
PopLess()
实例化要传递给PopLess
的类std::sort()
的临时实例。它实际上就像你说的那样(注意在这个例子中有一个额外的副本):
PopLess pl = PopLess();
sort(union, union + 60, pl);
然后,std::sort()
将调用该实例上的operator()
。
至于函数对象或函数指针是否更好“更好”,这取决于。可能最重要的区别是函数对象可以维持状态,而指针传递的普通函数则不能。编译器可能能够更好地优化其中一个,但在大多数使用场景中可能并不重要。
答案 1 :(得分:5)
问题1:
PopLess()
必须解决 像PopLess > tempObject.operator()
这样的东西 与执行运算符()相同 对临时对象起作用。
它没有像你说的那样扩展。 PopLess()
实际上是对隐式PopLess::PopLess()
构造函数的调用。此代码创建一个临时对象,并将其传递给函数调用中的第3个参数。
问题:2
我们是否有任何特别的优势 使用函数对象与 函数指针?
不是这种情况。这里你的PopLess对象是无状态的。您可以创建具有内部状态的仿函数(函数对象)。
示例:
struct ensure_min
{
int value;
ensure_min(int val) : value(val) {}
int operator()(const int& i)
{
return std::max(value, i);
}
}
std::vector<int> values;
values.push_back(-1);
values.push_back(0);
values.push_back(1);
values.push_back(2);
values.push_back(3);
std::transform(values.begin(), values.end(),
std::ostream_iterator<int>(std::cout, "\n"), ensure_min(1));
此代码将输出序列中的所有数字,确保输出中的所有数字都具有最小值1(输出为1 - 如果原始数字少于 - 或原始数字,如果原始数字大于或等于1)。
答案 2 :(得分:3)
Q1:PopLess()
构建类型为PopLess
且sort
的对象,然后使用此对象使用operator ()
对范围中的元素进行排序。
查看for_each
函数可能更容易,它可以像这样实现:
template <typename IterT, typename Function>
Function for_each( IterT first, IterT last, Function f ) {
for( ; first != last; ++first )
f(*first);
return f;
}
基本上for_each
和sort
以及使用函数对象的函数,只需获取函数对象的实例并调用其operator ()
。
Q2:当您使用函数对象而不是函数指针时,编译器可能能够通过内联来优化函数调用,这可能不像编译器直接使用函数指针那样。此外,函数对象可以具有状态。
答案 3 :(得分:2)
我不确定问题1的问题,但PopLess()是一个对象。在sort函数中,此对象调用了operator()方法来比较项目。
答案 4 :(得分:0)
答案 5 :(得分:0)
主要的实际区别是仿函数维持状态的能力。例如,对多列数据进行排序,仿函数可以在哪个列上排序,排序方向甚至整理规则(区分大小写等)。