C++ 谓词(predicate) 与 仿函数 ( functor (function object))

谓词与函数对象

谓词 predicate

C++ 标准定义谓词以下:html

The Predicate parameter is used whenever an algorithm expects a function object that when applied to the result of dereferencing the corresponding iterator returns a value testable as true. In other words, if an algorithm takes Predicate pred as its argument and first as its iterator argument, it should work correctly in the construct if (pred(*first)){...}. The function object pred shall not apply any non-constant function through the dereferenced iterator. This function object may be a pointer to function, or an object of a type with an appropriate function call operator.ios

换成中文就是:当一个算法须要一函数对象,去应用于解引用(deferencing)迭代器(deferencing 解释: int p;将定义一个指向整数的指针,并p取消引用该指针,这意味着它将实际检索p指向的数据。)的结果,谓词参数返回一个testable值为true。换句话说,换句话说, 若是算法将谓词 pred 做为其参数,first参数是迭代参数,则若是 (pred (* first)) {..} , 它应该在构造中正常工做。函数对象 pred 不该经过解引用迭代器应用于任何非定常(non-constant)函数。此函数对象能够是指向函数的指针, 也能够是具备适当函数调用运算符的类型的对象。算法

仿函数

functor(函数对象或函数)形式:object + ()
这包括正常函数,函数指针和 () 运算符(函数调用运算符)重载的类对象,即为其定义函数 operator()() 类。
有时咱们能够在普通函数不起做用时使用函数对象。STL常用函数对象并提供几个很是有用的函数对象。
函数对象是泛型编程的力量和纯抽象概念的另外一个例子。咱们能够说任何行为都像函数对象是函数。所以,若是咱们定义一个行为是函数的对象,它能够用做函数。编程

#include <iostream> 

struct absValue 
{ 
    float operator()(float f){ 
        return f> 0?f:-f; 
    } 
}; 

int main()
{ 
    using namespace std; 

    float f = -123.45; absValue aObj; 
    float abs_f = aObj(f); 
    cout <<“f =”<< f <<“abs_f =”<< abs_f << '\n'; 
    return 0; 
}

 

正如咱们从定义中看到的那样,即便 aObj 是一个对象而不是一个函数,咱们也能够对该对象进行调用。效果是运行由对象absValue定义的重载调用操做符。运算符获取浮点值并返回其绝对值。请注意,函数调用运算符必须声明为成员函数。
所以,定义调用操做符的类类型的对象(如absValue对象)称为函数对象。
一个函数的行为是能够经过使用括号和传递参数来调用。app

func (arg1 , arg2);

 

若是咱们但愿对象以这种方式运行,咱们必须经过使用括号和传递参数来调用它们。咱们所要作的就是使用适当的参数类型定义operator() :函数

Class X {
public:
    // define "function call" operator
    return-value operator() (arguments) const;
    ...
};

 

而后咱们可使用这个类的对象来表现咱们能够调用的函数:性能

X fn; 
//... 
fn(arg1,arg2); //为函数对象fn调用operator()

 

此调用至关于:优化

fn.operator()(ARG1,ARG2); //为函数对象fn调用operator()

 

一个例子:spa

class Print { 
publicvoid operator()(int elem)const { 
        cout << elem <<“”; 
    } 
}; 

int main(){ 
    vector <int> vect; 
    forint i = 1; i <10; ++ i){ 
        vect.push_back(i); 
    } 

    Print print_it; 
    for_each(vect.begin(),vect.end(),print_it); 
    cout << endl; 
    return 0; 
}

 

for_each(vect.begin(),vect.end(),print_it);

 

 一般,第三个参数能够是仿函数,而不只仅是常规函数。实际上,这提出了一个问题。咱们如何声明第三个参数?咱们不能将它声明为函数指针,由于函数指针指定了参数类型。由于容器几乎能够包含任何类型,因此咱们事先并不知道应该使用哪一种特定类型。STL经过使用模板解决了这个问题。.net

template<class Iterator, class Function>
Function for_each(Iterator first, Iterator last, Function f) {
    while (first != last) {
        f(*first);  
        ++first;
    }
    return f;
}

 

如下是Nicolai M. Josuttis在“The C ++ Standard Library”中列出的函数对象的一些优势。

  • 功能对象是“智能功能”。
    行为像指针的对象是智能指针。对于行为相似于函数的对象也是如此:它们能够是“智能函​​数”,由于它们可能具备超出operator()的能力。函数对象能够具备其余成员函数和属性。这意味着函数对象具备状态。

  • 每一个函数对象都有本身的类型。
    普通函数只有在签名不一样时才有不一样的类型。可是,当函数对象的签名相同时,它们能够具备不一样的类型。实际上,函数对象定义的每一个函数行为都有本身的类型。这是使用模板进行泛型编程的重大改进,由于您能够将功能行为做为模板参数传递。

  • 函数对象一般比普通函数更快。
    模板的概念一般容许更好的优化,由于在编译时定义了更多细节。所以,传递函数对象而不是普通函数一般会产生更好的性能。

STL改进了仿函数概念,以下所示:
generator : 是一种能够不带参数调用的函数
一元函数:有一个参数的调用函数
二元函数:有两个参数的调用函数

generator 能够被认为是一种 每次调用都返回 集合/序列的下一个值的函数/对象。

算法的特殊辅助函数是谓词。谓词是返回布尔值的函数(或者能够隐式转换为bool的函数)。换句话说,谓词类是一个仿函数类,其operator() 函数是谓词,即其operator() 返回true或false。
谓词在STL中被普遍使用。标准关联容器的比较函数是谓词,谓词函数一般做为参数传递给find_if等算法。根据其目的,谓词是一元的或二元的。
一元函数返回一个布尔值是一元谓词。
二元函数返回一个布尔值是二元谓词。

谓词的种类算法(algorithm) 的 谓词(predicate) 详解函数 函数指针 lambda表达式 函数对象 库定义的函数对象

转自:http://www.javashuo.com/article/p-gbzsawxw-gk.html

相关文章
相关标签/搜索