C++11 Change `auto` Lambda to a different Lambda?
Every lambda expression creates a new unique type, so the type of your first lambda is different from the type of your second (example). Additionally the copy-assignment operator of a lambda is defined as deleted (example) so you're doubly-unable to do this. For a similar effect, you can have a
be a std::function
object though it'll cost you some performance
std::function<bool()> a = [] { return true; };
a = [] { return false; };
transfer lambda to another lambda with different type
You can wrap f
with a lambda and forward it to testMethodOnInt
.
void testMethod(std::function<void(std::pair<std::string, int>)> f) {
testMethodOnInt([&](int x) { f({"", x}); });
}
How to use lambda auto parameters in C++11
C++11 doesn't support generic lambdas. That's what auto
in the lambda's parameter list actually stands for: a generic parameter, comparable to parameters in a function template. (Note that the const
isn't the problem here.)
Note: C++14 does support lambdas with
auto
,const auto
, etc. You can read about it here.
You have basically two options:
Type out the correct type instead of
auto
. Here it is the element type ofX
, which ispair<double, vector<int>>
. If you find this unreadable, a typedef can help.std::stable_sort(X.rbegin(), X.rend(),
[](const pair<double, vector<int>> & lhs,
const pair<double, vector<int>> & rhs)
{ return lhs.first < rhs.first; });Replace the lambda with a functor which has a call operator template. That's how generic lambdas are basically implemented behind the scene. The lambda is very generic, so consider putting it in some global utility header. (However do not
using namespace std;
but type outstd::
in case you put it in a header.)struct CompareFirst {
template <class Fst, class Snd>
bool operator()(const pair<Fst,Snd>& l, const pair<Fst,Snd>& r) const {
return l.first < r.first;
}
};std::stable_sort(X.rbegin(), X.rend(), CompareFirst());
Assigning a lambda within a switch statement
You can't do that because every lambda has unique type, and they can't be assigned to each other. You can use std::function
instead.
std::function<int(int,int,int,int)> valueFunction = [](int s, int d, int ct, int tt) { return -1; };
C++11 std::set lambda comparison function
Yes, a std::function
introduces nearly unavoidable indirection to your set
. While the compiler can always, in theory, figure out that all use of your set
's std::function
involves calling it on a lambda that is always the exact same lambda, that is both hard and extremely fragile.
Fragile, because before the compiler can prove to itself that all calls to that std::function
are actually calls to your lambda, it must prove that no access to your std::set
ever sets the std::function
to anything but your lambda. Which means it has to track down all possible routes to reach your std::set
in all compilation units and prove none of them do it.
This might be possible in some cases, but relatively innocuous changes could break it even if your compiler managed to prove it.
On the other hand, a functor with a stateless operator()
has easy to prove behavior, and optimizations involving that are everyday things.
So yes, in practice I'd suspect std::function
could be slower. On the other hand, std::function
solution is easier to maintain than the make_set
one, and exchanging programmer time for program performance is pretty fungible.
make_set
has the serious disadvantage that any such set
's type must be inferred from the call to make_set
. Often a set
stores persistent state, and not something you create on the stack then let fall out of scope.
If you created a static or global stateless lambda auto MyComp = [](A const&, A const&)->bool { ... }
, you can use the std::set<A, decltype(MyComp)>
syntax to create a set
that can persist, yet is easy for the compiler to optimize (because all instances of decltype(MyComp)
are stateless functors) and inline. I point this out, because you are sticking the set
in a struct
. (Or does your compiler support
struct Foo {
auto mySet = make_set<int>([](int l, int r){ return l<r; });
};
which I would find surprising!)
Finally, if you are worried about performance, consider that std::unordered_set
is much faster (at the cost of being unable to iterate over the contents in order, and having to write/find a good hash), and that a sorted std::vector
is better if you have a 2-phase "insert everything" then "query contents repeatedly". Simply stuff it into the vector
first, then sort
unique
erase
, then use the free equal_range
algorithm.
this' pointer changes in c++11 lambda
You capture start
by reference, but the variable start
and the contained lambda function get destroyed at the end of out()
.
Later the signal handler tries to call start()
, but the lambda function doesn't exist anymore. Maybe the memory where its this
was stored was overwritten in the mean time, causing unexpected output.
The call to print_something()
doesn't crash despite of the invalid this
because the function doesn't actually try to use this
. The printing in the function is independent of this
and the lookup of print_something
s address can happen at compile time so that calling the function doesn't access this
at runtime.
Using auto in lambda function declaration
A lambda expression does not result in a std::function
. Instead, it creates an unnamed unique class type and that has an overload for operator()
. When you pass your lambda to A
's constructor, it creates a temporary std::function
object, and you store a pointer to that temporary object. When A
's constructor ends, that temporary object is destroyed, leaving you with a dangling pointer.
To fix this, just get rid of using pointers. That would look like
#include <iostream>
#include <functional>
class A
{
std::function <void ()> m_Lambda;
public:
A(const std::function <void ()> lambda): m_Lambda (lambda) {}
void ExecuteLambda()
{
m_Lambda();
}
};
void main()
{
int i1 = 1;
int i2 = 2;
const auto lambda = [&]()
{
std::cout << "i1 == " << i1 << std::endl;
std::cout << "i2 == " << i2 << std::endl;
};
A a(lambda);
a.ExecuteLambda();
}
Type of a lambda function, using auto
Lambdas are meant to be used with either auto
or as template parameter. You never know the type of a lambda and you can't type it. Each lambda has it's own unique type. Even if you knew the name of the type, their type names usually contains character prohibited in type names.
Why does lambda have their own type? because in reality, the compiler create a class defined a bit like that:
struct /* unnamed */ {
// function body
auto operator()(int* a) const {
std::cout << *a << std::endl;
}
} print_int; // <- instance name
This code is very close to an equivalent (I omitted conversion operator).
As you can see, you already use auto, because lambdas are deducing the return type.
Some will say to use std::function<void(int*)>
, but I disagree. std::function
is a polymorphic wrapper around anything callable. Since lambdas are callable types, they fit into it. I other words, it work much like std::any
but with a call operator. It will induce overhead in your application.
So what should you do?
use auto
! auto
isn't bad. In fact, it can even make your code faster and reduce unnecessary typing. If you feel uncomfortable with auto
, well you shouldn't! auto
is great, especially if you don't have the choice ;)
In fact, you could avoid using auto
by using a template parameter:
template<typename F, typename Arg>
void parametric_print(F function, Arg&& arg) {
function(std::forward<Arg>(arg));
}
Then use it like this:
int main() {
int a = 3;
parametric_print([](int* a) {std::cout << *a << std::endl;}, &a);
}
There you go, no auto
! However, a template parameter is deduced with the same rule as auto
. In fact, concept are accepted into the C++20 standard with terse function templates. You could write the same function template like this:
// C++20
void parametric_print(auto function, auto&& arg) {
function(std::forward<decltype(arg)>(arg));
}
As mentionned by Oktalist, if concepts are accepted into the standard, then you could replace auto
with Callable
:
Callable print_int = [](int* a) { std::cout << *a << std::endl; };
But it does not result in a different type, it just enforce some rules when deducing the type.
What is a lambda expression in C++11?
The problem
C++ includes useful generic functions like std::for_each
and std::transform
, which can be very handy. Unfortunately they can also be quite cumbersome to use, particularly if the functor you would like to apply is unique to the particular function.
#include <algorithm>
#include <vector>
namespace {
struct f {
void operator()(int) {
// do something
}
};
}
void func(std::vector<int>& v) {
f f;
std::for_each(v.begin(), v.end(), f);
}
If you only use f
once and in that specific place it seems overkill to be writing a whole class just to do something trivial and one off.
In C++03 you might be tempted to write something like the following, to keep the functor local:
void func2(std::vector<int>& v) {
struct {
void operator()(int) {
// do something
}
} f;
std::for_each(v.begin(), v.end(), f);
}
however this is not allowed, f
cannot be passed to a template function in C++03.
The new solution
C++11 introduces lambdas allow you to write an inline, anonymous functor to replace the struct f
. For small simple examples this can be cleaner to read (it keeps everything in one place) and potentially simpler to maintain, for example in the simplest form:
void func3(std::vector<int>& v) {
std::for_each(v.begin(), v.end(), [](int) { /* do something here*/ });
}
Lambda functions are just syntactic sugar for anonymous functors.
Return types
In simple cases the return type of the lambda is deduced for you, e.g.:
void func4(std::vector<double>& v) {
std::transform(v.begin(), v.end(), v.begin(),
[](double d) { return d < 0.00001 ? 0 : d; }
);
}
however when you start to write more complex lambdas you will quickly encounter cases where the return type cannot be deduced by the compiler, e.g.:
void func4(std::vector<double>& v) {
std::transform(v.begin(), v.end(), v.begin(),
[](double d) {
if (d < 0.0001) {
return 0;
} else {
return d;
}
});
}
To resolve this you are allowed to explicitly specify a return type for a lambda function, using -> T
:
void func4(std::vector<double>& v) {
std::transform(v.begin(), v.end(), v.begin(),
[](double d) -> double {
if (d < 0.0001) {
return 0;
} else {
return d;
}
});
}
"Capturing" variables
So far we've not used anything other than what was passed to the lambda within it, but we can also use other variables, within the lambda. If you want to access other variables you can use the capture clause (the []
of the expression), which has so far been unused in these examples, e.g.:
void func5(std::vector<double>& v, const double& epsilon) {
std::transform(v.begin(), v.end(), v.begin(),
[epsilon](double d) -> double {
if (d < epsilon) {
return 0;
} else {
return d;
}
});
}
You can capture by both reference and value, which you can specify using &
and =
respectively:
[&epsilon, zeta]
captures epsilon by reference and zeta by value[&]
captures all variables used in the lambda by reference[=]
captures all variables used in the lambda by value[&, epsilon]
captures all variables used in the lambda by reference but captures epsilon by value[=, &epsilon]
captures all variables used in the lambda by value but captures epsilon by reference
The generated operator()
is const
by default, with the implication that captures will be const
when you access them by default. This has the effect that each call with the same input would produce the same result, however you can mark the lambda as mutable
to request that the operator()
that is produced is not const
.
Related Topics
Delete Pointer to Multidimensional Array in Class Through Another Pointer - How
Strange Exception Throw - Assign: Operation Not Permitted
How to Convert a Time into Epoch Time
Reference Invalidation After Applying Reverse_Iterator on a Custom Made Iterator
What Happen to Pointers When Vectors Need More Memory and Realocate Memory
Why Simple Console App Runs But Dialog Based Does Not Run in Win Ce 6.0
Is There Any 'Out-Of-The-Box' 2D/3D Plotting Library for C++
How to Overload the Conditional Operator
Const to Non-Const Conversion in C++
How to Make an Unordered Set of Pairs of Integers in C++
Symbol Not Found When Using Template Defined in a Library
Error: 'I' Does Not Name a Type with Auto
Strange Behavior with Constexpr Static Member Variable