C++模板化函子

发布于 2024-08-06 16:28:25 字数 81 浏览 4 评论 0原文

我想知道是否有人可以帮助我处理函子。我真的不明白函子是什么以及它们是如何工作的我尝试过谷歌搜索但我仍然不明白。函子如何工作以及它们如何与模板一起工作

I was wondering if anyone can help me with functors. I dont really understand what functors are and how they work I have tried googling it but i still dont get it. how do functors work and how do they work with templates

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

巴黎盛开的樱花 2024-08-13 16:28:25

函子基本上是一个“函数对象”。它是一个封装在类或结构中的单个函数,您可以将其传递给其他函数。

它们通过创建您自己的类或结构来工作,该类或结构会重载函数调用运算符(称为 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::transform。当然,您可以创建一个实例作为局部变量并将其传递,但​​这要方便得多。

现在,进入模板。 std::transform 中函子的类型是模板参数。这是因为 std::transform 不知道(或关心!)你的函子是什么类型。它所关心的是它定义了一个合适的operator(),为此它可以做类似的事情

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

它可以节省您相当多的打字时间。 ;)

A functor is basically a "function object". It's a single function which you have wrapped in a class or struct, and which you can pass to other functions.

They work by creating your own class or struct which overloads the function call operator (called operator() ). Typically, you create an instance of it by simply constructing it in-place as an argument to your function which takes a functor.

Suppose you have the following:

std::vector<int> counts;

Now, you want to increment all the counts that are contained in that vector. You could loop through them manually to increment them, or you could use a functor. A suitable functor, in this case, would look like this:

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

IncrementFunctor is now a functor which takes any integer and increments it. To apply it to counts, you can use the std::transform function, which takes a functor as an argument.

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

The syntax IncrementFunctor() creates an instance of that functor which is then passed directly to std::transform. You could, of course, create an instance as a local variable and pass it on, but this is much more convenient.

Now, onto templates. The type of the functor in std::transform is a template argument. This is because std::transform does not know (or care!) of which type your functor is. All it cares about is that it has a fitting operator() defined, for which it can do something like

newValue = functor(oldValue);

The compiler is pretty smart about templates, and can often figure out on its own what the template arguments are. In this case, the compiler realizes automatically that you're passing in a parameter of type IncrementFunctor, which is defined as a template type in std::transform. It does the same for the list, too, so the compiler automatically recognizes that the actual call would look like this:

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

It saves you quite a bit of typing. ;)

汐鸠 2024-08-13 16:28:25

函子是可以使用函数调用运算符调用的东西,在语法上通过附加(),并且可以选择在括号内添加参数列表。

这就是模板所需要的全部内容。就模板而言,调用此函数的对象是任何允许此语法的对象,或者换句话说,可以是自由函数,也可以是重写operator()()<的类的实例/代码>。 (“自由”函数只是一个不是成员的函数,也就是说,它是全局范围内的函数或先前包含的命名空间范围内的函数。)

在模板元编程之外,我们通常不会这样说自由函数是一个函子,并为重写operator()()的类实例保留该名称:

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

在C++中,模板是编译的,因此只要语法有意义 /em>,编译器会很乐意使用函数或函子:

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

A functor is something that can be invoked/called with the function call operator, syntactically by appending (), with optionally an argument list inside the parentheses.

That's all a template needs. The thing on which this is invoked, as far as a template is concerned, is anything that allows this syntax -- or in other words, either a free function or an instance of a class that overrides operator()(). (A "free" function is just one that isn't a member, that is, it's a function at global scope or a function at the scope of a previously included namespace.)

Outside of template metaprogramming, we usually don't say that a free function is a a functor, and reserve that name for an instance of a class that overrides operator()():

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

In C++ templates are compiled, so as long as the syntax makes sense, the compiler will happily use a function or a functor:

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
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文