Why can't I create a vector of lambdas (of the same type) in C++11?
Every lambda has a different type—even if they have the same signature. You must use a run-time encapsulating container such as std::function
if you want to do something like that.
e.g.:
std::vector<std::function<int()>> functors;
functors.push_back([&] { return 100; });
functors.push_back([&] { return 10; });
How to declare a vector of functions (lambdas)
Use std::function
with the corresponding type:
std::vector<std::function<void(void)>> vec;
vec.push_back([]()->void{});
In your case it would be std::function<void(std::string)>
.
The exact type of a lambda is meaningless per standard ([expr.prim.lambda]/3):
The type of the lambda-expression (which is also the type of the closure object) is a unique, unnamed non-union class type
Why can't we directly use lambdas without mentioning its type in some STL containers?
You have mixed up the function template and the class template. For both cases, for any code to appear, it must be instantiated. Let's look at each case:
The std::sort
is a function template which accepts the binary-predicate (i.e. callable compare function/ function objects) as its third parameter.
template< class RandomIt, class Compare >
constexpr void sort( RandomIt first, RandomIt last, Compare comp ); (since C++20)
^^^^^^^^^^^^
Here the compiler will try to determine template argument types (i.e. RandomIt
and Compare
) from the passed function parameters, so-called implicit instantiation will happen automatically if you do not explicitly mention them.
That means, one could also call the std::sort
with template parameters (explicit instantiation):
const auto compare = [](const int& num1, const int& num2) { ...
std::sort<std::vector<int>::iterator, decltype(compare)>(a.begin(), a.end(), compare);
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Whereas, the std::set
is a class template. As long as you do not specify the template parameters here, you will not get a concrete type.
A class template by itself is not a type, or an object, or any other entity. No code is generated from a source file that contains only template definitions. In order for any code to appear, a template must be instantiated: the template arguments must be provided so that the compiler can generate an actual class (or function, from a function template).
template<
class Key,
class Compare = std::less<Key>, // optional
class Allocator = std::allocator<Key>
> class set;
Here, the Compare
is optional but part of the std::set
's class template type, which can be replaced with the user defined compare function/ callable. Without providing the type of callable, the compiler can not instantiate the version of std::set
you want.
Further Reads:
The
std::pair
has compare operations defined. Hence, thePredicateLambda
is not required in your example code. I hope that it is for demonstration purpose.Since c++17 we have deduction guide, for a template class, by which one can simply write:
#include <set>
#include <tuple>
#include <string>
using namespace std::string_literals;
std::set st{ std::pair{1, "string"s} }; // st uses theOne can also provide own deduction guides
Since c++20 lambda expression is default constructible. Hence,
you may not need to pass thePredicateLambda
as argument to thest
, in the newer
compilers.std::set<std::pair<int, std::string>, decltype(PredicateLambda)> st;
Return the same type as a lambda expression passed as argument
You may use deduced return type:
template <typename F>
auto foo(F f) -> decltype(f())
{
return f();
}
And if F
takes some arguments :
template <typename F, typename ... Args>
auto foo(F f, Args&&...args) -> decltype(f(std::forward<Args>(args)...))
{
return f(std::forward<Args>(args)...);
}
If lambdas don't have a specified type, how does std::function accept a lambda?
The type is there. It’s just that you don’t know in advance what it is. Lambdas have type - just the standard says nothing about what that type is; it only gives the contracts that type has to fulfill. It’s up to the compiler implementers to decide what that type really is. And they don’t have to tell you. It’s not useful to know.
So you can deal with it just like you would deal with storage of any “generic” type. Namely: provide suitably aligned storage, then use placement new
to copy-construct or move-construct the object in that storage. None of it is specific to std::function
. If your job was to write a class that can store an arbitrary type, you’d do just that. And it’s what std::function
has to do as well.
std::function
implementers usually employ the small-object optimization. The class leaves some unused room in its body. If the object to be stored is of an alignment for which the empty room is suitable, and if it will fit in that unused room, then the storage will come from within the std::function
object itself. Otherwise, it’ll have to dynamically allocate the memory for it. That means that e.g. capture of intrinsic vector types (AVX, Neon, etc) - if such is possible - will usually make a lambda unfit for small object optimization storage within std::function
.
I'm making no claims as to whether or if the capture of intrinsic vector types is allowed, fruitful, sensible, or even possible. It's sometimes a minefield of corner cases and subtle platform bugs. I don't suggest anyone go and do it without full understanding of what's going on, and the ability to audit the resulting assembly as/when needed (implication: under pressure, typically at 4AM on the demo day, with the suits about to wake up soon - and already irked that they have to interrupt their golf play so early in the day just to watch the presenter sweat).
Lambda closure cannot be converted to std::function
Because you forgot a return
:
f([](int x, int y = 10) { return g(x,y); }, 20);
Without return
, your lambda doesn’t return a value, and C++ infers a void
return type.
Related Topics
Treating Memory Returned by Operator New(Sizeof(T) * N) as an Array
Can C++ Have Code in the Global Scope
How to Pause a Pthread Any Time I Want
Opencv Unable to Set Up Svm Parameters
Initializer List Not Working with Vector in Visual Studio 2012
Why Can't I Open Avi Video in Opencv
Using the Less Than Comparison Operator for Strings
C++ Templates Angle Brackets Pitfall - What Is the C++11 Fix
Do I Need an Extern "C" Block to Include Standard Posix C Headers
C++ Static Template Member, One Instance for Each Template Type
Boost Zip_Iterator and Std::Sort
For Purposes of Ordering, Is Atomic Read-Modify-Write One Operation or Two
What Is a Reference-To-Pointer
How to Make My Split Work Only on One Real Line and Be Capable to Skip Quoted Parts of String
Integer Division Rounding with Negatives in C++
Std::Ostringstream Printing the Address of the C-String Instead of Its Content
Why Callback Functions Needs to Be Static When Declared in Class