The documentation on the cppreference shows some interesting things: To begin with the definition of a simple function and a simple structure, they are necessary for an example, like lemmas in theorems:

struct Foo { Foo(int num) : num_(num) {} void print_add(int i) const { std::cout << num_+i << '\n'; } int num_; }; void print_num(int i) { std::cout << i << '\n'; } 

Next is the announcement:

 std::function<void(int)> f_display = print_num; 

I am interested in the template parameter, I thought: "is this the type of function?", Because I have never seen parentheses anywhere in the template parameter.

But then comes another interesting thing:

 std::function<void(const Foo&, int)> f_add_display = &Foo::print_add; 

the Foo::print_add takes an int as input, which is a template parameter

What type is it? Those. What is the general name for these types? There it is not written. And I can not google it. I understand that this is a target object, it contains a function call (a pointer to a method and an argument), but what role do the parentheses play here? I can not just be based on logic, here you need to read.

It is not necessary for me to chew, it will be enough to indicate that google to know more about this, or just to give a link to the necessary literature.

  • 2
    I'm not sure what the answer is. std::function is a more convenient version of old function pointers. std::function<void(int)> f_display = print_num; void(int) - the function returns nothing, takes an integer. std::function<void(const Foo&, int)> f_add_display = &Foo::print_add this function is non-static inside the structure, to call it, you need an instance of the structure, we create a pointer to the function that accepts this structure and makes a call. roughly speaking void f_add_display(const Foo& p1, int p2){ return p1.print_add(p2);} we have a pointer to this function. There's more about lambda .. - pavel
  • See an example sitev.ru/post/54 - helped? - sitev_ru
  • one
    @pavel in general, such types (template parameters) are very similar in syntax for declaring a pointer to a function \ method. But the second example contains a signature with a class, this is strange. - OlegUP
  • An excellent question, I did not suspect that std::function can store pointers to member functions. Excellent design std::function by the committee. - ixSci

4 answers 4

As it seems to me, the question is not so much about std::function , but rather about the argument of the template, which uses parentheses inside.

I am interested in the template parameter, I thought: "is this a type of function?"

Yes. This is exactly the type of function. Moreover, such a type entry has been allowed since time immemorial. But used in this form is not often. It was often necessary to observe the type "pointer to a function", usually specified using typedef . For example:

 typedef void(*FP)(int); 

In this case, FP is a type that is "a pointer to a function that returns void and accepts an int ."

At the same time, you can specify the type F - "a function that returns void and accepts an int ":

 typedef void(F)(int); // скобки вокруг F необязательны 

At the same time type F* it will be the same as FP . Those. wherever FP is used, F* can be used. For example:

 void func(int); FP fp1 = &func; F* fp2 = &func; fp2 = fp1; 

We now return to the templates. For some template class C :

 template <class T> class C { }; 

you can type C<F> , or, similar to the record of interest to us with parentheses C<void(int)> . It is easy to make sure that these types are equivalent.

With the adoption of c++11 form with parentheses can also be used in using :

 using F2 = void(int); 

Type F2 will be equivalent to type F


I will say a few words about the second example from the question, i.e. already relative to std::function .

The type of the expression &Foo::print_add is void(Foo::*)(int) (a pointer to a member function) and cannot be converted to void(const Foo&, int) (a pointer to a free function), which is specified as a template type. However, the implementation of std::function allows such a conversion (this is regulated by the Standard (paragraph 20.12.2 of the draft) ), and so on. to the right of = can stand as a pointer to the mentioned member function, or to a free function of the form void FreeFunction(const Foo&, int) . In this case, the definition of INVOKE (which is present in the description of std::function ) expands either to (t1.*f)(t2, ..., tN) (member function call) or to f(t1, t2, ..., tN) (free function call).

  • Can you write that for two cases (a free function and a member function), a different implementation will be used and you will provide a reference to the standard (this is in 20.9.2)? Still, the implementation and functionality are rather unobvious and it would be nice to explain it in more detail. - ixSci
  • @ixSci, hmm ... is there anything written in the Standard about implementation? There's just a sample constructor . - αλεχολυτ
  • See here - ixSci 1:58 pm
  • @ixSci, can be in your own words add to the answer, what you think is missing? - αλεχολυτ
  • one
    @ixSci, well, I do not know. The calling code will be generally identical. And initialization through bind even shorter. And the definition of the variable std::function is the same as the creation of a functor. PS For several paragraphs already turned out in the comments. No to add immediately to the answer :) - αλεχολυτ

I am interested in the template parameter, I thought: "is this a function type?

This is a callable object , i.e. any function or functor.

If we pass to std::function pointer to a non-static member function, then we can specify the calling context object on which this function is to be called. ( Almost like call in javascript )

You can read here

It’s a rule of thumb. remaining arguments are forwarded as arguments for the member function.

  • 2
    No, this is not a callable object, this is a call signature, which can also be called a function type - ixSci
  • @ixSci, you are right, said that this argument fits. - free_ze

This type of parameter is called a function with a given prototype, aka, an entity that can be called. English SO on the same topic

That is, this is void(int) inside std::function<void(int)> - a direct indication - the template wants to eat the function with the void(int) prototype.

Further. To create a functor from a non-static method, you need to have a reference to the object and a pointer to the method. Here they are:

 std::function<void(const Foo&, int)> f_add_display = &Foo::print_add; 

The first parameter = a constant reference to the Foo object, the second parameter is already the first argument of the Foo :: print_add method.

In fact, a non-static class method differs from a static one in that it implicitly (the zero parameter) transfers the reference to the object for which we call the method.

When we capture a method into a functor, we must also pass along to it to the functor a specific instance of the class.

  • I’ll add that a constant object reference is needed as print_add as the print_add member print_add declared as constant. - Harry
  • one
    No, it is not called “function pointer”, it is called “function type” - ixSci
  • What you say what the first parameter is is a dark forest. In the old standard, it is said that C ++ 2003, 5.2.2 There are two kinds of functions: (57) (9.3) .... 57) A static member function (9.4 ) is an ordinary function. (C ++ ISO / IEC 14882 2003-10-15) ... - bruziuz
  • But the description of reality is in a wonderful document - agner.org/optimize/calling_conventions.pdf , page 19. ... In Microsoft’s compilers and 64 bit Windows, all explicit parameters come thereafter. In this case, it’s possible to get a little bit more information ... and bruziuz

The type of function exists since C89. For an expression with a function type, only two operations are allowed - converting to a pointer to a function and calling a function.

typedef void (* FPtr) (int);

In this case, FPtr is a type that is "a pointer to a function that returns void and accepts an int with an agreement to call it governed by a calling convention (calling convention) C ++"

Below is an example of implementing your own std :: function for global functions:

 template <class T> struct SmallWrapper { public: SmallWrapper(T theFunc) : func(theFunc){} T* func; }; void test() { puts("test"); } int main() { SmallWrapper<void()> w(test); return 0' }