Lambda object declarations (std::function<>() / auto lambda = []()...) are always literals, right? So does that mean we should, for clarity, coding etiquette and even performance, always declare them const static just like any other scoped literal constant?
Lambda object declarations (std::function<>() / auto lambda = ...) are always literals, right?
No, lambdas are not literals. They can capture state from the enclosing scope and that can be non-const. Consider:
int f(int a, int b) {
auto lambda = [=](int x) { return a*x; };
return lambda(b);
}
If you add static there, the variable lambda will be shared by all the code that uses f, and it will only be initialized on the first call capturing the value of a from the first call to f. By not having it static each call to f will use it's own first argument.
While the example is very artificial, I hope it helps to clear the point.
Related
In my understanding, lambdas are supposed to behave similarly to functions and even extend their functionality.
Because of this, captureless lambdas can decay to function pointers:
auto x = +[] (int x) {return x + 5;} // + triggers conversion to function pointer.
However, I have not found a way to make a lambda function behave similarly to a member function.
For example, the following snippet does not work:
class MyClass() {
int x;
static constexpr auto member_lambda_func = [this] () {return x + 5;}; //Does not compile. Cannot capture this.
};
Furthermore, you can't even make a lambda which captures this decay into a pointer to member function.
Is there a work around for making lambda member functions?
Or is there a good reason not to?
Lambdas can decay to function pointers if they are captureless but they cannot decay to anything if they capture something. In particular, if it captures only this it cannot decay to member function pointer.
See cppreference.
Can lambda functions decay to a pointer to member function?
Short answer: No.
Lambdas can only convert to function pointers. And member function pointers are not function pointers (they aren't even pointers).
Furthermore only non-capturing lambdas an convert to function pointers. A lambda that captures this is a capturing lambda.
Something like this may be of use - I don't know for what purpose, but it is closest that I can think of to what you are asking for:
static constexpr auto member_lambda_func = [](const MyClass& self) {
return self.x + 5;
};
In C++, it is possible to separate the declaration and definition of functions. For example, it is quite normal to declare a function:
int Foo(int x);
in Foo.h and implement it in Foo.cpp. Is it possible to do something similar with lambdas? For example, define a
std::function<int(int)> bar;
in bar.h and implement it in bar.cpp as:
std::function<int(int)> bar = [](int n)
{
if (n >= 5)
return n;
return n*(n + 1);
};
Disclaimer: I have experience with lambdas in C#, but I have not used them in C++ very much.
You can't separate declaration and definition of lambdas, neither forward declare it. Its type is a unique unnamed closure type which is declared with the lambda expression. But you could do that with std::function objects, which is designed to be able to store any callable target, including lambdas.
As your sample code shown you've been using std::function, just note that for this case bar is a global variable indeed, and you need to use extern in header file to make it a declaration (not a definition).
// bar.h
extern std::function<int(int)> bar; // declaration
and
// bar.cpp
std::function<int(int)> bar = [](int n) // definition
{
if (n >= 5) return n;
return n*(n + 1);
};
Note again that this is not separate declaration and definition of lambda; It's just separate declaration and definition of a global variable bar with type std::function<int(int)>, which is initialized from a lambda expression.
Strictly speaking you can't
Quoting from cpp reference
The lambda expression is a prvalue expression whose value is (until
C++17)whose result object is (since C++17) an unnamed temporary object
of unique unnamed non-union non-aggregate class type, known as closure
type, which is declared (for the purposes of ADL) in the smallest
block scope, class scope, or namespace scope that contains the lambda
expression
So the lambda is a unnamed temporary object. You can bind the lambda to a l-value object(for eg std::function) and by regular rules about variable declaration you can separate the declaration and definition.
Forward declaration is not the correct term because lambdas in C++ are objects, not functions. The code:
std::function<int(int)> bar;
declares a variable and you're not forced to assign it (that type has a default value of "pointer to no function"). You can compile even calls to it... for example the code:
#include <functional>
#include <iostream>
int main(int argc, const char *argv[]) {
std::function<int(int)> bar;
std::cout << bar(21) << "\n";
return 0;
}
will compile cleanly (but of course will behave crazily at runtime).
That said you can assign a lambda to a compatible std::function variable and adding for example:
bar = [](int x){ return x*2; };
right before the call will result in a program that compiles fine and generates as output 42.
A few non-obvious things that can be surprising about lambdas in C++ (if you know other languages that have this concept) are that
Each lambda [..](...){...} has a different incompatible type, even if the signature is absolutely identical. You for example cannot declare a parameter of lambda type because the only way would be to use something like decltype([] ...) but then there would be no way to call the function as any other []... form at a call site would be incompatible. This is solved by std::function so if you have to pass lambdas around or store them in containers you must use std::function.
Lambdas can capture locals by value (but they're const unless you declare the lambda mutable) or by reference (but guaranteeing the lifetime of the referenced object will not be shorter than the lifetime of the lambda is up to the programmer). C++ has no garbage collector and this is something needed to solve correctly the "upward funarg" problem (you can work-around by capturing smart pointers, but you must pay attention to reference loops to avoid leaks).
Differently from other languages lambdas can be copied and when you copy them you're taking a snapshot of their internal captured by-value variables. This can be very surprising for mutable state and this is I think the reason for which captured by-value values are const by default.
A way to rationalize and remember many of the details about lambdas is that code like:
std::function<int(int)> timesK(int k) {
return [k](int x){ return x*k; };
}
is basically like
std::function<int(int)> timesK(int k) {
struct __Lambda6502 {
int k;
__Lambda6502(int k) : k(k) {}
int operator()(int x) {
return x * k;
}
};
return __Lambda6502(k);
}
with one subtle difference that even lambda capturing references can be copied (normally classes containing references as members cannot).
I'm trying to design a C++ macro that needs to look something like this:
#define MY_MACRO(OBJECT, METHOD) \
[](BaseClass* obj) \
{ \
return static_cast<decltype(OBJECT)>(obj)->METHOD();\
}
Basically, a macro that translates into a lambda that calls a given method on a given object. But the lambda needs to take a base class of the object as a parameter (My use case guarantees that the cast will always work). Furthermore, the method to be called might not be on the base class.
The usage for this macro is that I have another method which I cannot modify declared as:
void Foo(std::function<int(BaseClass*)>);
and I need to be able to call it using my macro as a parameter like so:
T x;
Foo(MY_MACRO(x, method)); // match std::function<int(T*)>
However, the macro code doesn't work because I'm not capturing OBJECT, so it's not in scope when I need to pass it to decltype. Conceptually though, all the information the compiler needs is there... How can I do this? Is it possible?
A few constraints:
The lambda's parameter needs to be BaseClass. I can't make it decltype(OBJECT).
My situation does not allow me to capture OBJECT.
I don't have access to the C++14 feature of generalized lambda captures.
I need access to the type of the object without capturing it.
You can do it directly. You are required to capture only when you odr-use the named entity, and unevaluated operands, like those of decltype, don't odr-use anything. This is perfectly fine:
void f(){
int x;
[]{ decltype(x) y = 0; };
}
You can add an optional parameter to the lambda with the type that you want, and use decltype on that parameter. Here's an example of the pattern, minus the macro:
int main() {
int foo = 4;
auto lambda = [](double* bar, decltype(foo)* TP = nullptr) {
return static_cast<std::remove_pointer<decltype(TP)>::type>(*bar);
};
double x = 5;
return lambda(&x);
}
I get a pointer to decltype(foo) here because pointer types can easily be defaulted to nullptr to ensure that the parameter is optional. If decltype(foo) already resolves to a pointer type, as in your case if I got it right, you wouldn't need it (and the remove_pointer).
Here's an attempt:
template <typename T>
auto lambda_maker(int (T::* MF)())
{
return [](T* p) -> int { return (p->*MF)(); };
}
#define MY_MACRO(OBJ, METH) lambda_maker<decltype(OBJ)>(METH)
I want to shorten the following type of lambdas:
[] (SomeVeryLongTemplateType<int, float, char, std::string>, AnotherLongType) {};
Since the only reason for this lambda is to initialize some class std::function<...> member - it doesn't capture anything, it doesn't have argument names, it returns nothing, it does nothing.
If the shortening operation is expressed as a function of the number of arguments in signature, then I want this function to have the complexity O(1).
Is there a way to do that?
Looks like you're looking for an empty lambda which does nothing, so that your std::function object will always be in callable state!
If so, then use this one which can be reused, for any number of parameters:
static const struct empty_lambda_t //static and const applies to the object!
{
template<typename ...T>
void operator()(T && ... ) const {} //does nothing
}empty_lambda {}; //declare an object which is static and const
And then use it as:
std::function<void()> fun1 = empty_lambda;
std::function<void(int,int)> fun2 = empty_lambda;
std::function<void(whatever)> fun3 = empty_lambda;
Hope that helps.
in C++14 there will be "generic lambdas" that should simplify long type names in parameters as I understand:
auto lambda = [](auto x, auto y) {return x + y; };
here auto is like Template type
http://en.wikipedia.org/wiki/C%2B%2B14#Generic_lambdas
You're looking for "polymorphic lambdas". They do not exist (yet), so no.
However, you can make it easier with proper use of typedefs, so you don't have to type the entire thing every single time.
I'd like to get my mucky paws on the operator() of a lambda function. The following seems up the task:
template <typename F>
void bar(F func) {
void (F ::*pm)();
pm = &F::operator();
}
However, in the following, I need to include the mutable keyword. Why is that? Is it possible to above instead declare a pointer to member function, which can target arbitrary lambdas?
int main(int argc, char *argv[])
{
bar([]() mutable {});
return 0;
}
According to 5.1.2 of the N3291 C++0x specification, the lambda's operator() is const unless you explicitly declare it mutable:
This function call operator is declared const (9.3.1) if and only if the lambda-
expression’s parameter-declaration-clause is not followed by mutable.
You may be able to do some template metaprogramming magic to detect which is which.
However, it should be noted that, once func goes out of scope, you can't use that member pointer anymore. And it is a member pointer, not a function pointer, so you can't convert between the two.
C++0x lambdas are const by default, unlike the rest of the language. Consequently, your member-function variable must be const as well. The following should work:
template<typename F>
void bar(F func) {
typedef void (F::*pm_t)() const;
pm_t pm = &F::operator();
}
Consider this:
int x=0;
auto show = [x]() mutable
{
x++;
};
show();
The variable 'x' is being captured by-value, and without mutable, you cannot modify the local copy of this variable. Specify mutable to enable modification of this local copy. For by-value captures, it doesn't matter if value is modified, the original x variable won't be modified.