As mentioned in a similarly worded question (Why use bind over lambdas in c++14?) The answer was - no reason (and also mentioned why it would be better to use lambdas).
My question is - if in C++14 there was no longer a reason to use bind, why did the standards committee found it necessary to add std::bind_front in C++20?
Does it now have any new advantage over a lambda?
bind_front binds the first X parameters, but if the callable calls for more parameters, they get tacked onto the end. This makes bind_front very readable when you're only binding the first few parameters of a function.
The obvious example would be creating a callable for a member function that is bound to a specific instance:
type *instance = ...;
//lambda
auto func = [instance](auto &&... args) -> decltype(auto) {return instance->function(std::forward<decltype(args)>(args)...);}
//bind
auto func = std::bind_front(&type::function, instance);
The bind_front version is a lot less noisy. It gets right to the point, having exactly 3 named things: bind_front, the member function to be called, and the instance on which it will be called. And that's all that our situation calls for: a marker to denote that we're creating a binding of the first parameters of a function, the function to be bound, and the parameter we want to bind. There is no extraneous syntax or other details.
By contrast, the lambda has a lot of stuff we just don't care about at this location. The auto... args bit, the std::forward stuff, etc. It's a bit harder to figure out what it's doing, and it's definitely much longer to read.
Note that bind_front doesn't allow bind's placeholders at all, so it's not really a replacement. It's more a shorthand for the most useful forms of bind.
The paper that proposed it Simplified partial function application has some good compelling use cases. I will summarize them here, because otherwise I would have to quote most of the paper, so definitely go check it out:
Automatic perfect forwarding
Using a lambda would involve std::forward boilerplate
Propagating mutability
In case of storing object by value std::bind and std::bind_front propagate constness, but in the case of capturing lambda the user must chose a mutable or const version creating problems
Preserving return type
Using a lambda would involve -> decltype(auto) boilerplate on the user side.
Preserving value category
Like preserving mutability, except now we are talking about lvalue/rvalue and only std::bind_front does this correctly
Supporting one-shot invocation
A consequence of propagating mutability and preserving value category
Preserving exception specification
This is especially more important now since exception specification is now part of type system
cppreference has some useful notes as well:
This function is intended to replace std::bind. Unlike std::bind, it
does not support arbitrary argument rearrangement and has no special
treatment for nested bind-expressions or std::reference_wrappers. On
the other hand, it pays attention to the value category of the call
wrapper object and propagates exception specification of the
underlying call operator.
Related
C++20 introduces DefaultConstructible lambdas. However, cppreference.com states that this is only for stateless lambdas:
If no captures are specified, the closure type has a defaulted default constructor. Otherwise, it has no default constructor (this includes the case when there is a capture-default, even if it does not actually capture anything).
Why does this not extend to lambdas that capture things that are DefaultConstructible? For instance, why can [p{std::make_unique<int>(0)}](){ return p.get(); } not be DefaultConstructible, where the captured p would be nullptr?
Edit: For those asking why we would want this, the behavior only seems natural because one is forced to write something like this when calling standard algorithms that require functors to be default-constructible:
struct S{
S() = default;
int* operator()() const { return p.get(); }
std::unique_ptr<int> p;
};
So, we can pass in S{std::make_unique<int>(0)}, which does the same thing.
It seems like it would be much better to be able to write [p{std::make_unique<int>(0)}](){ return p.get(); } versus creating a struct that does the same thing.
There are two reasons not to do it: conceptual and safety.
Despite the desires of some C++ programmers, lambdas are not meant to be a short syntax for a struct with an overloaded operator(). That is what C++ lambdas are made of, but that's not what lambdas are.
Conceptually, a C++ lambda is supposed to be a C++ approximation of a lambda function. The capture functionality is not meant to be a way to write members of a struct; it's supposed to mimic the proper lexical scoping capabilities of lambdas. That's why they exist.
Creating such a lambda (initially, not by copy/move of an existing one) outside of the lexical scope that it was defined within is conceptually vacuous. It doesn't make sense to write a thing bound to a lexical scope, then create it outside of the scope it was built for.
That's also why you cannot access those members outside of the lambda. Because, even though they could be public members, they exist to implement proper lexical scoping. They're implementation details.
To construct a "lambda" that "captures variables" without actually capturing anything only makes sense from a meta-programming perspective. That is, it only makes sense when focusing on what lambdas happen to be made of, rather than what they are. A lambda is implemented as a C++ struct with captures as members, and the capture expressions don't even technically have to name local variables, so those members could theoretically be value initialized.
If you are unconvinced by the conceptual argument, let's talk safety. What you want to do is declare that any lambda shall be default constructible if all of its captures are non-reference captures and are of default constructible types. This invites disaster. Why?
Because the writer of many such lambdas didn't ask for that. If a lambda captures a unique_ptr<T> by moving from a variable that points to an object, it is 100% valid (under the current rules) for the code inside that lambda to assume that the captured value points to an object. Default construction, while syntactically valid, is semantically nonsense in this case.
With a proper named type, a user can easily control if it is default constructible or not. And therefore, if it doesn't make sense to default construct a particular type, they can forbid it. With lambdas, there is no such syntax; you have to impose an answer on everyone. And the safest answer for capturing lambdas, the one that is guaranteed to never break code, is "no."
By contrast, default construction of captureless lambdas can never be incorrect. Such functions are "pure" (with respect to the contents of the functor, since the functor has no contents). This also matches with the above conceptual argument: a captureless lambda has no proper lexical scope and therefore spawning it anywhere, even outside of its original scope, is fine.
If you want the behavior of a named struct... just make a named struct. You don't even need to default the default constructor; you'll get one by default (if you declare no other constructors).
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 6 years ago.
Improve this question
Everytime I think about the design of my class I ask myself these questions, should I use the pass by value, should I overload on const lvalue reference and rvalue reference or should I use perfect forwarding.
Often I use pass by value as having cheap to move types and I almost never use perfect forwarding. I overload when having only 1 parameter, maybe 2 if i really need the perf.
What do you do ?
Do you have easy rules of thumb to decide how to pass arguments, for member/non member functions but also for constructors and all the copy/assignment guys.
Thanks.
So all of the following is opinion-based, but these are the rules I tend to follow when thinking about an API. As always in C++, there are many ways to accomplish the same thing, and people will have different view on exactly what is best.
There are three kinds of parameters we need to think about: in parameters, out parameters, and in/out parameters. The latter two are simple, so we'll cover them first.
Out parameters
Don't use them. Seriously. If your function is going to return a new object, then return it by value. If you're going to return multiple new objects, then return them by value packed in a std::tuple (or std::pair). The caller can use std::tie (or structured bindings in C++17) to unpack them again. This gives the caller the maximum flexibility, and with RVO it's no less efficient than any other method.
In/out parameters
For functions which modify an already-constructed value, use a mutable lvalue reference, i.e. T&. This will prevent callers from passing a temporary, but that's actually a good thing: what would be the point of modifying something you're just going to throw away? Not that some style guides (notably Google's, but also Qt) advocate using a raw pointer (T*) in this situation, so that it's obvious at the call site that the argument will be modified (because you need to say f(&arg)), but I personally don't find this convincing.
In parameters
For pure input parameters, where the function will not modify the argument passed to it, things are a tiny bit more complicated. In general, the best advice is to pass by lvalue-reference-to-const, that is, const T&. This will allow the caller to pass both lvalues and rvalues. However, for small objects (sizeof(T) <= sizeof(void*)), such as int, it can be more efficient to pass by value instead.
An exception though is if you're going to take a copy of a passed argument, for example in a constructor; in this case, it's better to take the parameter by value, because the compiler can turn this into a move for rvalues.
What about T&&?
There are two circumstances where it's appropriate to use arguments of the form T&&. The first is templated forwarding functions where the type of the parameter is the template type, i.e.
template <typename T>
decltype(auto) func(T&& arg) {
return other_func(std::forward<T>(arg));
}
In this case, although the parameter looks as if it's an rvalue reference, it's actually a forwarding reference (sometimes called a universal reference). Only use a forwarding reference to pass things on to another function via std::forward; if you care about the value category of the argument, then T&& is not appropriate.
The second case is for real rvalue references, where the argument type is not a template parameter. In a very limited number of cases, it can be appropriate to overload on both the const arg& and arg&& forms, to avoid an unnecessary move. This should only be necessary in performance-critical situations in which you're going to copy or move the argument somewhere (for example, std::vector does this for its push_back() method) -- in general I would say it's better to take the argument by value and then move it into place.
Interfaces should express intent.
Optimisations should happen when users complain.
To me, the following interfaces have different meanings:
void foo(thing const& t); // "I won't modify your t. If it's copyable, I might copy it, but that's none of your concern."
void foo(thing t); // "Pass me a copy if you wish, or a temporary, or move your thing into me. What I do with t is up to me".
void foo(thing& t); // "t will be modified."
What follows now is only for "default" behavior. Like "normal" not really big types ("normal sized" vectors, strings etc.) nothing which seems to be very expensive in the first place.
In short:
Do whatever you like but be consistent.
There is no best practice which can guarantee you the best performance.
Some detail to this:
I was once on a conference having 3 popular C++ people (Herb Sutter, Andrei Alexandrescu and Scott Meyers) discuss this problem and each had another opinion on the best "default" behavior.
All by const-reference or by perfect-forwarding or just by-value.
So you won't get a perfect answer here. Compilers also can optimize differently etc.
Here is my personal opinion on this:
What I do is I prefer the by-value approach and if I later notice some thing becoming slow I start to optimize. I assume modern compilers being smart enough to avoid unnecessary copies and also maybe just move the object when they see it's no longer used afterwards. I try to keep in mind Return Value Optimization to let the compiler more easier optimize here if necessary (either return only one object or only r-values).
Though I have heard this behavior and optimization potential changing from compiler to compiler. So like said before: use what you prefer / stick to one way so it's consistent.
C++'s lambdas would be convenient to use in templates that need function objects but alas, they cannot be default constructed.
As discussed in this question, this makes sense for lambdas that have a non-empty capture-list.
Instantiating C++ lambda by its type
Kerrek explains:
The code doesn't make sense. Imagine you have a capturing lambda like
this:
{
int n = 0;
auto t = [&n](int a) -> int { return n += a; };
}
What could it possibly mean to default-construct an object of type
decltype(t)?
What about lambdas with an empty capture-list? Is there a reason those also don't make sense to default construct? Is there anything more to it than "the standard says so"?
In general, lambdas where specified as little as possible to solve specific use cases.
Other possibly useful things, like "a lambda that only copies trivially copyable data must be trivially copyable" was also omitted. (The standard does not specify if a lambda is trivially copyable or not)
The upside is that it makes lambda an easier to implement feature, which is important. The downside is that this rules out certain uses that are not in the "intended" set.
If you think that "a capture free lambda must have a zero-argument constructor" is an important thing, propose it. But this takes one use of lambdas (easy local capture and creation of function objects) and morphs it into something else (easy creation of stateless function objects whose types can be passed around).
In the paper about resumable functions, in the section about restrictions three restrictions are listed:
Resumable functions cannot use a variable number of arguments. For situations where varargs are necessary,the argument unwrapping may be placed in a function that calls a resumable function after doing the unwrapping of arguments.
The return type of a resumable function must be future<T> or shared_future<T>. The restrictions on T are defined by std::future, not this proposal, but T must be a copyable or movable type, or ‘void’. It must also be possible to construct a variable of T without an argument; that is, it has to have an accessible (implicit or explicit) default constructor if it is of a class type.
Await expressions may not appear within the body of an exception handler and should not be executed while a lock on any kind is being held by the executing thread.
There must be a reason behind this restrictions and due to my lack of knowledge about concurrency I cannot deduce what reasons are. Could someone enlight me about this topic?
Variable number of arguments
This restriction is referring to the C-style variadic functions or the C++11 variadic template ones?
If is the C-style ones, the reason of the limitation is related to the magic trickery done by the va_* macros?
If is referring to the variadric template functions I assume that the limitation must be related with the unpacking of the parameter pack not with the fact that the function is a template one (there's no wording about template resumable functions, so I assume that they're legal).
In both cases, I thought that the compiler could be smart enough to deduce which function to use.
Default constructible and copyable/movable type
I understand the reason behind returning a std::future or std::shared_future, but I'm guessing that the reason of the limitation behind the usable types is related to the types that the futures could use.
So, the paper is proposing to extend the language with two new keywords (resumable and await) that provides the behaviour of resumable functions but in the end it trust on existent constructs to transfer the return values of resumable functions between the function and the caller.
Why not propose some kind of language extension for the return values too? that could (maybe) release the limitation to default constructible and copyable/movable types and fix the assimetry between the return type and the returned type:
It should thus be noted that there is an asymmetry between the function’s observed behavior from the outside (caller) and the inside: the outside perspective is that function returns a value of type future<T> at the first suspension point, while the inside perspective is that the function returns a value of type T via a return statement (...)
No awaitable exception handlers nor awaitable locked threads
I guess that awaiting something while catching an exception have no sense, but I haven't any clue about the limitation of the locked threads.
I'm pretty sure all of these restrictions are related to the fact that the context of a resumable function has to be "saved" and "resumed" - I expect the mechanism will create a temporary "copy of the stack" or something similar. So:
Variable number of arguments
This really means things using va_arg functionality - not because the macros involved, but because it's impossible for an outside agent to know the number of actual arguments - for printf, you'd have to read the format string, for some others the last one is marked with NULL. So how much context needs to be saved away?
Locked threads
So we have just said "we don't want this thread to be interrupted", and then we go and say "Now lets run something else". That's like saying "Please, under no circumstances shall I be interrupted while I take my bath" while stepping into the bath and at the same time say "Can you phone me in 2 minutes..." - assuming the bath takes more than 2 minutes, one of those will be untrue.
Default constructible
I'm pretty sure the logic here is that it would make the whole concept quite complex if the return value to be constructed has to have arguments passed to the constructor. How would you even describe such a thing? And you would also have to "hold on to" those arguments while in suspended state. Again, making the saving of the context more complex.
I'm confident I get the general gist of the constructs, but I can't see the purpose of them in c++. I have read the previous posts on the topic here on SO and elsewhere, but I fail to see why they should be a new language feature.
The things I would like answered is thusly
What is the difference between a lambda and a template argument accepting a function/functor.
Is a closure just a functor with some set object state (scope?)?
What is the "killer app" for these constructs? or perhaps the typical use case?
Lambdas are really just syntactic sugar for a functor. You could do it all yourself: defining a new class, making member variables to hold the captured values and references, hooking them up in the constructor, writing operator()(), and finally creating an instance and passing it. Or you could use a lambda that's 1/10 as much code and works the same.
Lambdas which don't capture can be converted to function pointers. All lambdas can be converted to std::function, or get their own unique type which works well in templated algorithms accepting a functor.
Ok, you're actually asking a bunch of different questions, possibly because you are not fully familiar with terminology. I'll try to answer all.
What's the difference between a lambda and "operator()"? - Let's reword this to, "What's the difference between a lambda and object with operator()?"
Basically, nothing. The main difference is that a lambda expression creates a functional object while an object with an operator() IS a functional object. The end result is similar enough to consider the same though, an entity that can be invoked with the (params) syntax.
What's the difference between a closure and a functor? This is also rather confused. Please review this link:
http://en.wikipedia.org/wiki/Closure_(computer_programming)
http://en.wikipedia.org/wiki/Closure_(computer_programming)#C.2B.2B
So, as you can see, a closure is a kind of "functor" that is defined within a scope such that it absorbs the variables available to it within that scope. In other words, its a function that is built on the fly, during the operation of the program and that building process is parameterized by the runtime values of the scope containing it. So, in C++ closures are lambdas that use values within the function building the lambda.
What is the difference between a lambda and a template argument accepting a function/functor? - This is again confused. The difference is that they are nothing alike, really. A template "argument" accepting a function/functor is already confused wording so I'll assume by "argument" you mean "function", because arguments don't accept anything. In this case, although a lambda can accept a functor as an argument, it can't be templated, one. Two, generally the lambda is the one being passed as an argument to a function accepting a functor argument.
Is a closure just a functor with some set object state (scope?)?
As you can see by the above link, no. In fact, a closure doesn't even have state, really. A closure is built based UPON the state of some other entity that built it, within that functor though this isn't state, it's the very construction of the object.
What is the "killer app" for these constructs? or perhaps the typical use case?
I'll reword that to, "Why are these things useful?"
Well, in general the ability to treat any object as a function if it has operator() is extremely useful for a whole array of things. For one, it allows us to extend the behavior of any stdlib algorithm by using either objects or free functions. It's impossible to inummerate the vast supply of usefulnesses this has.
More specifically speaking of lambda expressions, they simply make this process yet easier. The limitations imposed by object definitions made the process of using stdlib algorithms slightly inefficient in some cases (from a development use perspective, not program efficiency). For one thing, at the time at least any object passed as a parameter to a template had to be externally defined. I believe that's also changing, but still...having to create entire objects just to perform basic things, that only get used in one place, is inconvenient. Lambda expressions allow that definition to be quite easy, within the scope of the place its being used, etc, etc...