函数对象与函数指针

时间:2010-06-09 00:55:53

标签: c++ algorithm stl function-pointers function-object

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


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

提前感谢您的帮助。

6 个答案:

答案 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()构建类型为PopLesssort的对象,然后使用此对象使用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_eachsort以及使用函数对象的函数,只需获取函数对象的实例并调用其operator ()

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

答案 3 :(得分:2)

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

答案 4 :(得分:0)

  • 问题1:PopLess()是一个临时对象。
  • 问题2:它允许你的 拥有国家的“功能”......你可以 用任何东西初始化对象 你喜欢它之前用它作为一个 功能

答案 5 :(得分:0)

主要的实际区别是仿函数维持状态的能力。例如,对多列数据进行排序,仿函数可以在哪个列上排序,排序方向甚至整理规则(区分大小写等)。