Hello I have this text from C++ Primer 5th edition:
function<bool (const string&)> fcn = &string::empty;
find_if(svec.begin(), svec.end(), fcn);
Here we tell function that empty is a function that can be called with a string and returns a bool. Ordinarily, the object on which a member function executes is passed to the implicit this parameter. When we want to use function to generate a callable for a member function, we have to “translate” the code to make that implicit parameter explicit.
So what he meant with: "When we want to use function... make that implicit parameter explicit"?
It refers to the implicit this parameter to member functions. They get a pointer to the current object passed under the hood. std::function has some magic to turn that implicit parameter into an explicit one:
#include <iostream>
#include <functional>
struct foo {
void bar() { std::cout << "Hello World\n";}
};
int main() {
std::function< void (foo&)> g = &foo::bar;
foo f;
f.bar(); // bar takes no parameters, but implicitly it gets a pointer to f
g(f); // g(f) explicitly gets the parameter
}
With f.bar() its the method call syntax that tells us that we call bar on the object f. f can be said to be an implicit parameter to bar. With g(f) that parameter is passed explicitly.
PS: Of course it isn't "magic", but I understood the question is about the general meaning of the implicit parameter, while explaining how std::function turns member functions into free callables is perhaps a topic for a different question.
Related
I am confused about using C++ function pointers.
using fn_p1 = void(int); // function pointer
using fn_p2 = void (*)(int);
void functional(fn_p1 f) {
f(1);
}
void callback(int value){
// do something
}
int main() {
fn_p2 f = callback; //works
fn_p1 f1 = static_cast<fn_p1>(f); //does not work
fn_p1 f2 = callback; //does not work
fn_p1 f2 = static_cast<fn_p1>(callback); //does not work
functional(f); // works, the argument is form of void(*)(int)
f(1); // works
functional(*f); // works, the argument is dereferenced, void(int)
(*f)(1); // works
return 0;
}
I know there is no difference if you call a function pointer with f(1), (*f)(1), or (*****f)(1).
I don't get how functional(f); works but fn_p1 f1 = static_cast<fn_p1>(f); and its variants can not since they define the function pointer as using fn_p1 = void(int);.
Could anyone explain how the function pointer works or how the compiler deals with it?
The most useful error that the IDE should give you is on the line fn_p1 f2 = callback;:
Illegal initializer (only variables can be initialized) [illegal_initializer]
(This is the message I get from clangd.)
That means literally that an entity of type void(int) (or more in general someReturnType(someArgTypes...)) is not a variable.
Indeed, in C++ functions are not first class, which means that you can't pass them to function and don't get them in return from function; when you think you are successfully doing so, you're in reality passing or taking back function pointers.
In other words there's no such a thing in C++ as "a function value". Functions are not values that you can assign to.
When you write
fn_p1 f2 = callback; // assuming using fn_p1 = void(int);
you are truly trying to create a variable of type void(int). But such a thing doesn't exist, hence the error.
The static_casts don't work for fundamentally the same reason.
As regards
void functional(fn_p1 f) {
f(1);
}
function-to-(function)pointer decaying is happening. f is truly of type fn_p1*.
You can easily verify it by writing an invalid statement in functional in order to trigger a compiler error telling you what the type of f is, like this
void functional(fn_p1 f) {
int foo = f;
f(1);
}
Clangd answers this
Cannot initialize a variable of type 'int' with an lvalue of type 'fn_p1 *' (aka 'void (*)(int)') [init_conversion_failed]
which indirectly tells you that f is of type fn_p1*, so you better write that instead of fn_p1 as the type of the parameter of functional, at least for clarity (similarly to how you should prefer writing T* instead of T[] as a parameter type in a function taking a c-style array of Ts).
If you truly want to assign functions to variables, you should look at lambdas, structs+operator(), std::function, and the topic of function objects in general.
void(*)(void) is a function pointer while I suppose void(void) is also a way to represent function type. It is used as template parameter in std::function <functional>
What is void(void) and how it is different from void(*)(void)?
What is void(void) and how it is different from void(*)(void)?
They are distinct types. Although the former(void(void)) can be implicitly converted to the latter(void(*)(void)) in many contexts.
The type void(void) is called a function type. The following are also function types:
int (int, int) //this is a function type
void(int) //this is a function type as well
On the other hand, void (*)(void) is a pointer to a function type. That is, it is a pointer that points to a function with 0 parameters and return type of void.
TL;DR
The void(void) is a specification of a function type, it's
signature.
The void(*)(void) is a pointer to function.
These are distinct.
First, let's start by saying, that sometimes the void(void) will be automatically treated as a pointer to function (i.e. in a parameter list). We still can be explicit and use the void(*)(void), but the void(void) will be an equivalent in these cases.
// Here, we explicitly state that the f is a pointer to function
void foo(void (*f)(void), int i);
// Equivalent, f is automatically treated as a pointer to the function
void foo(void f(void), int i);
This will not be the case for the mentioned std::function for example. The types of the two are different, yet may have similar behavior (i.e. we can use the function call operator on a pointer to function).
void bar();
// Prints 1
std::cout << std::is_same<void(void), decltype(bar)>::value << '\n';
// Prints 1 as well
// Note the pointer type specifier
std::cout << std::is_same<void(*)(void), decltype(bar)*>::value << '\n';
// Prints 0
// Note the absence of the pointer type specifier
std::cout << std::is_same<void(*)(void), decltype(bar)>::value << '\n';
And particularly:
// Ok
std::function<decltype(bar)> fn1 = bar;
// error: variable ‘std::function<void (*)()> fn2’ has initializer but incomplete type
std::function<decltype(bar)*> fn2 = bar;
Note, that we can however "store" a pointer to a member function in std::function, but even then the template's parameter still won't be of a pointer to function type, but a plain function signature.
struct MyType {
void func(int) {}
};
int main() {
// Note, we can't have a member function without an instance of the type
// Thus we specify the usually implicit first param and the explicit int param
std::function<void(MyType&, int)> fn_mem = &MyType::func;
MyType my_object;
fn_mem(my_object, 21);
}
For more on std::function please refer to the reference. In short, the use of the std::function instead of the function pointers has the same moto as using the smart pointers instead of the raw pointers.
You may wonder on other uses of the void(void) or int(int) style function type specifications, so here's another example you may see often:
using func_t = int(int);
// func_ptr_func return a pointer to the func_t type alias
func_t* func_ptr_func();
N.B. unlike in the case of a parameter, the compiler won't treat the function type in a return as a pointer to function type. Thus, we must explicitly specify the pointer type in case of the return.
// Here, baz is a function that doesn't take any agruments
// And returns a pointer to a function that takes an int argument and "returns" void
void (*baz())(int);
for void fun(){}, std::is_same_v<void(void)>, decltype(fun)> is true; and std::is_same_v<void(*)(void)>, decltype(&fun)> is true. In fact, those are their real types. However, the standard approve you convert an object that has type void(void) to void(*)(void) implicitly (so you can even write (******funptr)()), that's why we always confuse them.
I'm working with std::bind but I still don't get how it works when we use it with member class functions.
If we have the following function:
double my_divide (double x, double y) {return x/y;}
I understand perfectly well the next lines of code:
auto fn_half = std::bind (my_divide,_1,2); // returns x/2
std::cout << fn_half(10) << '\n'; // 5
But now, with the following code where we have a bind to member function I have some questions.
struct Foo {
void print_sum(int n1, int n2)
{
std::cout << n1+n2 << '\n';
}
int data = 10;
};
Foo foo;
auto f = std::bind(&Foo::print_sum, &foo, 95, _1);
f(5);
Why is the first argument a reference? I'd like to get a theoretical explanation.
The second argument is a reference to the object and it's for me the most complicated part to understand. I think it's because std::bind needs a context, am I right? Is always like this? Has std::bind some sort of implementation to require a reference when the first argument is a member function?
When you say "the first argument is a reference" you surely meant to say "the first argument is a pointer": the & operator takes the address of an object, yielding a pointer.
Before answering this question, let's briefly step back and look at your first use of std::bind() when you use
std::bind(my_divide, 2, 2)
you provide a function. When a function is passed anywhere it decays into a pointer. The above expression is equivalent to this one, explicitly taking the address
std::bind(&my_divide, 2, 2)
The first argument to std::bind() is an object identifying how to call a function. In the above case it is a pointer to function with type double(*)(double, double). Any other callable object with a suitable function call operator would do, too.
Since member functions are quite common, std::bind() provides support for dealing with pointer to member functions. When you use &print_sum you just get a pointer to a member function, i.e., an entity of type void (Foo::*)(int, int). While function names implicitly decay to pointers to functions, i.e., the & can be omitted, the same is not true for member functions (or data members, for that matter): to get a pointer to a member function it is necessary to use the &.
Note that a pointer to member is specific to a class but it can be used with any object that class. That is, it is independent of any particular object. C++ doesn't have a direct way to get a member function directly bound to an object (I think in C# you can obtain functions directly bound to an object by using an object with an applied member name; however, it is 10+ years since I last programmed a bit of C#).
Internally, std::bind() detects that a pointer to a member function is passed and most likely turns it into a callable objects, e.g., by use std::mem_fn() with its first argument. Since a non-static member function needs an object, the first argument to the resolution callable object is either a reference or a [smart] pointer to an object of the appropriate class.
To use a pointer to member function an object is needed. When using a pointer to member with std::bind() the second argument to std::bind() correspondingly needs to specify when the object is coming from. In your example
std::bind(&Foo::print_sum, &foo, 95, _1)
the resulting callable object uses &foo, i.e., a pointer to foo (of type Foo*) as the object. std::bind() is smart enough to use anything which looks like a pointer, anything convertible to a reference of the appropriate type (like std::reference_wrapper<Foo>), or a [copy] of an object as the object when the first argument is a pointer to member.
I suspect, you have never seen a pointer to member - otherwise it would be quite clear. Here is a simple example:
#include <iostream>
struct Foo {
int value;
void f() { std::cout << "f(" << this->value << ")\n"; }
void g() { std::cout << "g(" << this->value << ")\n"; }
};
void apply(Foo* foo1, Foo* foo2, void (Foo::*fun)()) {
(foo1->*fun)(); // call fun on the object foo1
(foo2->*fun)(); // call fun on the object foo2
}
int main() {
Foo foo1{1};
Foo foo2{2};
apply(&foo1, &foo2, &Foo::f);
apply(&foo1, &foo2, &Foo::g);
}
The function apply() simply gets two pointers to Foo objects and a pointer to a member function. It calls the member function pointed to with each of the objects. This funny ->* operator is applying a pointer to a member to a pointer to an object. There is also a .* operator which applies a pointer to a member to an object (or, as they behave just like objects, a reference to an object). Since a pointer to a member function needs an object, it is necessary to use this operator which asks for an object. Internally, std::bind() arranges the same to happen.
When apply() is called with the two pointers and &Foo::f it behaves exactly the same as if the member f() would be called on the respective objects. Likewise when calling apply() with the two pointers and &Foo::g it behaves exactly the same as if the member g() would be called on the respective objects (the semantic behavior is the same but the compiler is likely to have a much harder time inlining functions and typically fails doing so when pointers to members are involved).
From std::bind docs:
bind( F&& f, Args&&... args ); where f is a Callable, in your case that is a pointer to member function. This kind of pointers has some special syntax compared to pointers to usual functions:
typedef void (Foo::*FooMemberPtr)(int, int);
// obtain the pointer to a member function
FooMemberPtr a = &Foo::print_sum; //instead of just a = my_divide
// use it
(foo.*a)(1, 2) //instead of a(1, 2)
std::bind(and std::invoke in general) covers all these cases in a uniform way. If f is a pointer-to-member of Foo, then the first Arg provided to bind is expected to be an instance of Foo (bind(&Foo::print_sum, foo, ...) also works, but foo is copied) or a pointer to Foo, like in example you had.
Here is some more reading about pointers to members, and 1 and 2 gives full information about what bind expects and how it invokes stored function.
You also can use lambdas instead std::bind, which could be more clear:
auto f = [&](int n) { return foo.print_sum(95, n); }
Can i actually use a function overloading like this:
#include <iostream>
void foo(...)
{
std::cout << "::foo(...) \n";
}
void foo(int)
{
std::cout << "::foo(int) \n";
}
int main()
{
foo(0);
foo('A');
foo("str");
foo(0, 1);
}
What standard says about it? And in what kind of situations i'll get ::foo(...)?
void foo(int)
will accept one argument of type int.
void foo(...)
accepts any number of arguments, of any type. It will be selected when the call doesn't have a single int argument. Not very useful, in general.
Also note that it is undefined behavior to pass objects of class type to ....
In N3337 I can see:-
13.3.2 Viable functions
A candidate function having fewer than m parameters is viable only if
it has an ellipsis in its parameter list (8.3.5). For the purposes of
overload resolution, any argument for which there is no corresponding
parameter is considered to “match the ellipsis” (13.3.3.1.3) .
When you declare a function in the following way :
void foo (...)
this mean foo accepts any number of arguments.
So this function will be called when this is the must suitable one.
In your case whenever you won't write :
foo(//Some single int).
In your specific main, this will happen :
foo(0) //Calls foo(int).
foo('A) //Calls foo (int). as you can convert a char to an int.
foo("str") //Calls foo(...) . as you can not convert a string to an int.
foo(1,2) //Calls foo(...) . as this is the only possible function
cause the second foo function only takes one int.
void foo(...) will take variable arguments. And it will be called when there the no or type of argument does not match the provided argument list of other function with the same function name.
foo(0); //This will call void foo(int) function
foo('A'); //This will call void foo(int) function
foo("str"); //This will call void foo(...) function
foo(0, 1); //This will call void foo(...) function
NOTE:
Although the ellipsis works fine with function overloading, it is not highly recommend pursuing variadic functions. At least not until you have significantly more experience in C++ to understand the pitfalls. I would suggest its use only with the try catch block where there are situations when the error cannot be predicted.
This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
How does dereferencing of a function pointer happen?
If we have
void f() {
printf("called");
}
Then the following code will result in output of "calledcalled":
f();
(*f)();
I don't really understand how this works…what is the difference between *f and f? And why would you call a function using the latter syntax?
There are two ways to call a function in C++:
By name:
f();
Through a function pointer:
typedef void (*fptr_t)();
fptr_t fptr = &f;
(*fptr)();
Now, using the address-of operator on a function name (&f) obviously creates a function pointer. But the function name can implicitly convert to a function pointer when certain conditions are met. So the above code could be written as:
typedef void (*fptr_t)();
fptr_t fptr = f; // no address-of operator, implicit conversion
(*fptr)();
Your second example is doing exactly this, but using a temporary variable to hold the function pointer instead of a named local variable.
I prefer to use address-of when creating function pointers, the meaning is much clearer.
A related note: The function call operator will automatically dereference a function pointer if one is provided. So this also is legal:
typedef void (*fptr_t)();
fptr_t fptr = &f;
fptr();
That's pretty useful with templates, because the same syntax works whether you have a function pointer or a functor (object implementing operator()) passed in.
And neither shortcut works with pointer-to-members, there you NEED explicit address-of and dereference operators.
In C, #Mehrdad explains that all function calls use a function pointer.
The first one is somewhat of a syntactic sugar for the second one. The second one makes it obvious that you're making the call through a pointer, and it's used mainly with function pointers rather than regular functions, to make the distinction more obvious.
Just as an array type is almost entirely equivalent to the corresponding pointer-to-element type, a function type is entirely equivalent to the corresponding pointer-to-function type:
void (*func1)() = f; // function type -> pointer-to-function type
void (*func2)() = &f; // pointer-to-function type -> pointer-to-function type
and also
void (*func)() = ...;
func(); // pointer-to-function type + function-call operator
(*func)(); // function type + function-call operator
So, in
(*f)();
you're dereferencing f (implicitly converted to &f), and then apply the function-call operator.