10

我有两个与函数对象和函数指针有关的问题,


问题: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”一书。
我无法解码主题内容,因此已发布寻求帮助。

在此先感谢您的帮助。

4

6 回答 6

8

PopLess()实例化PopLess要传递给的类的临时实例std::sort()。这实际上与您要说的相同(请注意,在此示例中制作了一个额外的副本):

PopLess pl = PopLess();
sort(union, union + 60, pl);

然后,std::sort()将调用该operator()实例。

至于函数对象或函数指针是否更好“更好”,这取决于。可能最重要的区别是函数对象可以保持状态,而指针传递的普通函数则不能。编译器可能能够更好地优化其中之一,但在大多数使用场景中,这可能并不重要。

于 2010-06-09T01:04:57.100 回答
5

问题一:

PopLess()必须解析为类似于PopLess > tempObject.operator()在临时对象上执行 operator () 函数的东西。

它不是[如你所说的那样扩展]。PopLess()实际上是对隐式PopLess::PopLess()构造函数的调用。此代码创建一个临时对象并将其传递给函数调用中的第三个参数。

问题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)。

于 2010-06-09T08:39:04.790 回答
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_eachandsort和 使用函数对象的函数,只需获取函数对象的实例并调用它的operator ().

Q2:当您使用函数对象而不是函数指针时,编译器可能能够通过内联优化函数调用,这对于编译器来说可能不像函数指针那样直接。此外,函数对象可以具有状态。

于 2010-06-09T01:08:16.413 回答
2

我不确定问题 1 在问什么,但 PopLess() 是一个对象。在 sort 函数内部,这个对象调用了它的 operator() 方法来比较项目。

于 2010-06-09T01:05:21.660 回答
0
  • 问题一:PopLess() 是一个临时对象。
  • 问题2:它允许你的“函数”有状态......你可以在它被用作函数之前用你喜欢的任何东西初始化对象
于 2010-06-09T01:05:13.470 回答
0

主要的实际区别是函子保持状态的能力。例如,对多列数据进行排序,仿函数可以具有关于排序依据的列、排序方向甚至排序规则(区分大小写等)的信息。

于 2010-06-12T17:01:26.697 回答