What Is the Type of Lambda When Deduced With "Auto" in C++11

What is the type of lambda when deduced with auto in C++11?

The type of a lambda expression is unspecified.

But they are generally mere syntactic sugar for functors. A lambda is translated directly into a functor. Anything inside the [] are turned into constructor parameters and members of the functor object, and the parameters inside () are turned into parameters for the functor's operator().

A lambda which captures no variables (nothing inside the []'s) can be converted into a function pointer (MSVC2010 doesn't support this, if that's your compiler, but this conversion is part of the standard).

But the actual type of the lambda isn't a function pointer. It's some unspecified functor type.

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.

c++ lambda auto type deduction

What's the difference between the two?

The difference between the two is that in the first case:

auto f1 = [](int x) {return x;};
decltype(f1) f2 = [](int y) {return y;};

The type of f1 (and thus of decltype(f1), so the type of f2) is the type of the first lambda and, taking into account that every lambda is of different type, you can't assign the second lambda to a variable of the type of the first lambda.

In the second case:

std::function<int (int)> f1 = [](int x) {return x;};
decltype(f1) f2 = [](int y) {return y;};

The type of f1 (and thus of decltype(f1), so the type of f2) is std::function<int(int)>, that isn't the type of the first or second lambda, but is compatible with both. Compatible in the sense that both lambdas can be assigned to a std::function<int(int)>.

What is lambda functions type? C++

The actual type of a lambda is specified as a "unique closure type" that corresponds to the lambda expression.

Its name isn't specified. Its layout even isn't fully specified. It's almost entirely an implementation defined type, of a name one usually doesn't know nor care about.

And when you think about it, you (the developer) don't really need to know what its "actual name" is. You can refer to it just fine:

using my_lambda_type = decltype(x);

There's another aspect to your question, that beyond the closure type being implementation defined, the behavior of std::type_info::name is itself implementation defined. You are printing an implementation defined name for an implementation defined type via an entirely implementation defined mechanism.

There's very little you can glean (C++-wise) from it other than details about your current compiler implementation.

What's type deduced by auto in lambda expression used to modify a vector of type bool (special container)

Calling std::vector<T>::operator[] on a non-const vector object returns a
std::vector<T>::reference, which in most cases is T&.

However, in the case of std::vector<bool>, its internal storage may be optimized to store multiple bools as bits in a single byte, instead of using a normal bool[] array, in which case reference cannot be a normal bool&. It is instead a proxy object that has operator= and operator bool() implemented to assign/read a specific bool element in the vector's internal representation.

The type of that proxy is unspecified and implementation-specific, but auto can still deduce it.

C++11 does not deduce type when std::function or lambda functions are involved

The issue is on the nature of lambdas. They are function objects with a fixed set of properties according to the standard, but they are not a function. The standard determines that lambdas can be converted into std::function<> with the exact types of arguments and, if they have no state, function pointers.

But that does not mean that a lambda is a std::function nor a function pointer. They are unique types implementing operator().

Type deduction, on the other hand, will only deduce exact types, with no conversions (other than const/volatile qualifications). Because the lambda is not a std::function the compiler cannot deduce the type in the call: filter(mySet,[](int i) { return i%2==0; }); to be any std::function<> instantiation.

As of the other examples, in the first one you convert the lambda to the function type, and then pass that. The compiler can deduce the type there, as in the third example where the std::function is an rvalue (temporary) of the same type.

If you provide the instantiating type int to the template, second working example, deduction does not come into play the compiler will use the type and then convert the lambda to the appropriate type.

deduce return type of lambda with arguments

If you are willing to limit yourself to non-generic lambdas (and in general to class objects with exactly one operator() overload), then something like this should work (not tested):

template <typename T, typename R, typename... Args>
R ResultOf(R (T::*)(Args...));

Used as

using R = decltype(ResultOf(&decltype(my_lambda)::operator()));

This could be wrapped in helper classes for nicer syntax; we leave this as an exercise for the reader.

C++ 20 lambda in template: unable to deduce ‘auto*’ from lambda

Wrapper expects function pointer, but template argument deduction won't consider implicit conversion (from lambda without capture to function pointer).

You can convert the lambda to function pointer explicitly:

int main(){
return Wrapper<static_cast<int(*)()>([](){return 42;})>()();
}

or

int main(){
return Wrapper<+[](){return 42;}>()();
}

LIVE

Can I get return type auto to work with lambdas of the same signature but different captures?

Am I seeing problems because they specify different captures?

You would have seen a problem even if they were exactly the same, token for token.

Each lambda expression creates a unique closure type, which is different from any closure type created by any other lambda. There is no reconciling this difference, so auto deduction cannot succeed.

You'll need to type erase the actual functor if you intend to return two different lambdas (either with std::function, or a custom type that supports move only semantics). That, or perhaps roll the entire logic into a single lambda:

auto
get_func()
{
auto i = std::make_unique<int>(2);
return [i=std::move(i)]() {
if (*i == 1) {
return *i;
}
return 2;
};
}

Why can we avoid specifying the type in a lambda capture?

From cppreference:

A capture with an initializer acts as if it declares and explicitly captures a variable declared with type auto, whose declarative region is the body of the lambda expression (that is, it is not in scope within its initializer), [...]

Lambdas used the opportunity of a syntax that was anyhow fresh and new to get some things right and allow a nice and terse syntax. For example lambdas operator() is const and you need to opt-out via mutable instead of the default non-const of member functions.

No auto in this place does not create any issues or ambiguities. The example from cppreference:

int x = 4;
auto y = [&r = x, x = x + 1]()->int
{
r += 2;
return x * x;
}(); // updates ::x to 6 and initializes y to 25.

From the lambda syntax it is clear that &r is a by reference capture initialized by x and x is a by value capture initialized by x + 1. The types can be deduced from the initializers. There would be no gain in requiring to add auto.



In my experience n could have been just declared inside the lambda body with auto or int as datatype. Isnt it?

Yes, but then it would need to be static. This produces the same output in your example:

std::generate(v.begin(), v.end(), [] () mutable { 
static int n = 0;
return n++; });

However, the capture can be considered cleaner than the function local static.



Related Topics



Leave a reply



Submit