Why cpp std::function can hold capture-lambda, while function pointer cannot? - c++

I've got this code snippet:
int x = 3;
auto fauto = [=](){ cout<<'x'; };
function<void()> func{fauto};
func();
void (*rawPf)() = fauto; // fail to compile
rawPf();
I knew the syntax that only non-capture lambda can be assigned to function pointer. But:
(1) Why std::function can hold capture-lambda?
(2) as both std::function and function pointers are callable, what's the core difference that makes std::function able to hold capture-lambda, while function pointer cannot?
Any detailed explanation on language design for this?

Why can a function pointer not hold a lambda with a capture : because a Lambda is NOT a function ,it's an object!
Why can a lambda without a capture be converted to a function pointer ?
A Lambda is just an ordinairy object (a piece of data) of a compiler generated class (with a unique classname that only the compiler knows) with a function-operator member (i.e. auto operator() ( ??? )) that the compiler defines for you with the parameter definitions (if any) you provide. The data-members of a lambda-object are defined by the capture-list and/or usage of variables of its enclosing scope.
All non-static member functions when called on an object get a implicit hidden argument called this. This is also the case when you 'call' the lambda.
Now ,when you don't capture something ,the lambda has no data (empty class) and the compiler doesn't have to generate an implicit this pointer for the call ,which makes the function operator just like an ordinairy function and the compiler can convert it to function pointer.
So it not the lambda that is converted to a function-pointer ,it's the lambda's function-operator that is converted.
Why can std::function hold both : because it's a template and with templates and specializations you can do almost anything.

There's no reason not to implement it in std::function<>, so it's implemented.
The reason a function pointer cannot hold a capture lambda is that the latter has a this pointer and there's no place to store that in the function pointer (well, unless you compile new code or assign it from a pool). However, std::function<> can allocate arbitrary amount of space, amongst these, the this pointer.
You can understand this better if you try to implement a function returning function pointers for lambdas (which, when called, by specification should call the lambda).

Related

How to understand this std::bind usage

I am trying to understand this usage of std::bind().
For this example:
std::bind(&TrtNodeValidator::IsTensorRTCandidate, &validator, std::placeholders::_1)
They are trying to bind the function TrtNodeValidator::IsTensorRTCandidate(). However, according to the definition of this API:
Status TrtNodeValidator::IsTensorRTCandidate(const Node* node);
It only accepts one parameter. Why do they still need &validator when there exits std::placeholders::_1?
TrtNodeValidator::IsTensorRTCandidate() is a non-static member function.
Aside from its explicit parameters, it requires a TrtNodeValidator* to become its implicit this parameter.
This usage:
std::bind(&TrtNodeValidator::IsTensorRTCandidate, &validator,
std::placeholders::_1)
will produce a callable object that then calls:
(&validator)->IsTensorRTCandidate(std::placeholders::_1)

Function which converts from from a_func(A a_in) to b_func(B b_in) (c++)

I have a class of function (call it AFunc) which takes a parameter of type A, and a class of function (call it BFunc) which takes a parallel parameter of type B (i.e. there is a straightforward conversion from objects of type A to those of type B).
I need to write a function like the following:
using Afunc = AReturnType(*)(A);
using BFunc = BReturnType(*)(B);
BFunc convertFunction(AFunc a_func_in)
{
BReturnType(*b_func_out) =
[&](B b_in) {
A a_in = A(b_in);
AReturnType a_out = a_func_in(a_in);
return BReturnType(a_out);
};
return b_func_out;
}
That is, a function which takes a function compatible with A types and returns a function compatible with B types.
My first thought was to define a function within the conversion function, but I quickly discovered that local functions are not supported in c++. My next thought was to use a lambda expression as above, but I have since learned that lambda functions can only be decayed to function pointers if they don't capture any references, however in this case the lambda needs to be aware of the AFunc parameter provided to the wider conversion function.
This is where I've run out of ideas. Is there any other way of doing this?
The problem is that having a function pointer is stronger than simply having a callable object. The latter could be a function pointer, but it could also be a closure or a functor, both of which carry state. A function pointer is just that: a pointer to a function. No state, no special tricks. Just one chunk of code that can be executed on demand.
So, at least, there's no way to pass an AFunc at runtime and get a BFunc, the way you've defined everything, because that would involve generating new functions in the code itself at runtime, which C++ doesn't allow.
However, if you know the AFunc you want to apply this too at compile-time, we can use templates to get the same result. A template is evaluated at compile-time and actually generates code, so we can use it to come up with functions which have genuine function pointers. In fact, we're not even going to write a conversion function; we're just going to write our BFunc and then template parameterize it.
template <AFunc f>
BReturnType bFunc(B b) {
return f(b);
}
Assuming the appropriate conversions exist, you can write something like BFunc b = bFunc<sampleAFunc>; and the compiler will generate the appropriate function (and corresponding pointer) for you.

How std::bind works with member functions

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); }

c++11 what is the scope for the lambda function below

quick question on lambda functions. I saw that when using the gcc complier there is an implicit cast to a function pointer for the operator() function of the lambda if it doesn't have a capture. As a result looking at this watered down example below what should I expect the life time of this function to be available for callback? What scope is the lambda function defined at? local scope, package scope, global scope? Is there any problem with calling the lambda after the function exits in this case? I am not looking to use std::function here at all, so please don't respond with a std::function return value for a solution. My question is really just to understand the scope of that function (without capture) and if it is available for the lifetime of the program.
#include <iostream>
typedef int(*fPtrT)(int,int);
fPtrT fx() {
return static_cast<fPtrT>([](int i, int j){return i+j;});
}
int main()
{
std::cout << fx()(5,2) << std::endl;
}
A lambda expression returns an instance of an anonymously-defined class (the type is known only to the compiler). This class overloads the operator () to serve as a function object.
On top of that, lambda expressions that don't close over any state have the added specification that they can be implicitly converted to a C-style function pointer. In those cases, imagine that the operator () just invokes a static function (and the implicit conversion is a pointer to that static function).
Knowing all of this, we can say the following things about the code you posted:
Every time the fx function is invoked, an instance of the anonymous class is created
This instance is an r-value; as such it only exists until the end of the statement
The function pointer returned by the fx function is effectively a pointer to a static function
The function pointer can be safely used by whoever has possession of it (because it is a static function with no shared state)
A lambda that doesn't capture anything is safe to use anywhere.
If it captures by reference then it's only safe within the lifetime of the objects it refers to.
If it captures by value then it's safe anywhere – it's just an object.

Wrapped lambda expressions

Here's a lamba wrapper expression defined:
function <int(double)> f =
[](double x) -> int{ return static_cast <int> (x*x); };
It is used like this:
f(someintvalue);
What is the difference between normal functions and wrapped lambdas?
question is - what is the difference between normal function and wrapped lambda?
Normal function is a normal function and what you call "wrapped lambda" is actually a function object.
By the way, why use std::function? You could simply write this:
auto f = [](double x) { return static_cast <int> (x*x); };
//call
int result = f(100.0);
Also, I omitted the return type, as it is implicitly known to the compiler from the return expression. No need to write -> int in the lambda expression.
Lambdas can capture surrounding scope ([=] or [&]) resulting in anonymous structs that contain a member function.
Certain tasks, like accessing lambda (types) across Translation Units, or taking standard pointer-to-memberfunction addresses from lambdas may prove hard/useless because the actual type of the automatically generated 'anonymous' type cannot be known (and is in fact implementation defined).
std::function<> was designed to alleviate exactly that problem: being able to bind a function pointer (semantically) to a lambda (or indeed, whatever callable object)
1: in fact the type can have external linkage, but you cannot portably refer to that from another translation unit because the actual type is implementation defined (and need not even be expressible in C++ code; within the original TU you'd be able to use decltype to get the magic type. Thanks, Luc for the good precisions about this)