2009-10-06 172 views
1

我想知道是否有人可以用函子帮我。我真的不明白函数是什么以及它们是如何工作的我试着用Google搜索它,但我仍然没有得到它。仿函数是如何工作的以及它们如何与模板配合使用C++模板仿函数

回答

6

仿函数基本上是一个“函数对象”。这是一个单独的函数,你已经包装在一个类或结构中,并且可以传递给其他函数。

他们通过创建自己的类或结构来重载函数调用操作符(称为operator())来工作。通常,通过简单地将它构造为函数的参数来创建它的一个实例,该函数需要一个函子。

假设你有以下几点:

std::vector<int> counts; 

现在,你要增加所有包含该矢量计数。你可以通过手动循环来增加它们,或者你可以使用一个仿函数。合适的仿函数,在这种情况下,应该是这样的:现在

struct IncrementFunctor 
{ 
    int operator() (int i) 
    { 
     return i + 1; 
    } 
} 

IncrementFunctor是一个仿函数这需要任意整数,并增加它。要将其应用于计数,您可以使用std :: transform函数,该函数将函子作为参数。

std::transform(
    counts.begin(),  // the start of the input range 
    counts.end(),   // the end of the input range 
    counts.begin(),  // the place where transform should place new values. 
          // in this case, we put it right back into the original list. 
    IncrementFunctor()); // an instance of your functor 

语法IncrementFunctor()创建函子,然后将其直接传递到std ::变换的一个实例。当然,您可以创建一个实例作为局部变量并将其传递,但​​这样更方便。

现在,到模板上。 std :: transform中函子的类型是一个模板参数。这是因为std :: transform不知道(或关心!)你函子的类型。它所关心的是,它有一个合适的运营商()定义,它可以这样做

newValue = functor(oldValue); 

编译器是非常聪明的模板,往往可以找出自身的模板参数是什么。在这种情况下,编译器会自动实现您传递的类型为IncrementFunctor的参数,该参数在std :: transform中定义为模板类型。它为列表中的相同,也因此编译器会自动识别出实际调用是这样的:

std::transform<std::vector<int>::iterator, // type of the input iterator 
       std::vector<int>::iterator, // type of the output iterator 
       IncrementFunctor>(   // type of your functor 
    counts.begin(),  // the start of the input range 
    counts.end(),   // the end of the input range 
    counts.begin(),  // the place where transform should place new values. 
          // in this case, we put it right back into the original list. 
    IncrementFunctor()); // an instance of your functor 

它可以节省你不少打字。 )

5

函子是一些可以被调用/被叫与函数调用操作,语法上通过附加(),任选括号内的参数列表。

这就是所有模板的需求。就模板而言,它被调用的东西是允许这种语法的任何东西 - 换句话说,可以是自由函数或覆盖operator()()的类的实例。 (一个“free”函数只是一个不是成员的函数,也就是说,它是全局作用域的函数,或者是以前包含的名称空间范围的函数。)

外模板元编程的,我们通常不说,一个自由的功能是AA函子,并保留该名称为覆盖operator()()一个类的实例:

struct Foo { 
public: 
    void operator()(int i) { // do something } 
    void operator()(int i, char x) { // do something else } 
} 

在C++模板编译,所以只要在语法有道理,编译器会很乐意用一个函数或仿函数:

template<typename T> class Bar { 
    private int j ; 
    public: 
    Bar(int i) : j(i) {} 
    void doIt(T t) { 
    t(j) ; 
    } 
} 

Foo f; 
extern void resize(int i) ; // in some header 

Bar<Foo> bf(5) ; 
// a Bar that is templated on Foo 
Bar< void (&)(int) > br(5) ; 
// a Bar that is templated on a function taking int and returning void 

br.doit(&resize) ; // call resize with br.j 
bf.doit(f) ; // call Foo::operator()(int) on Foo f with bf.j 
+0

+1,一个更好的答案,因为你确实表现出_templated_仿函数的例子。 – 2009-10-06 23:51:36

+0

虽然这个'void(&(int))'语法怎么了?这个用法至少不是C++。它是C++/CLI吗? “ – 2009-10-06 23:57:54

+0

”这个void(&(int))语法怎么了?“?是的,这是“一个函数的地址int和返回void”的错误。 – tpdi 2009-10-07 00:48:27