I have read the item31 of "Effective Modern C++" and web page of http://en.cppreference.com/w/cpp/language/lambda and wonder if I can define a lambda by its definite type instead of the wrapped type of std::function or keyword of auto and how can I accomplish that.
for instance, for the type int:
auto x_1 = 5; // type deduction
int x_2 = 5; // defined by definite type
// both x_1, x_2 are int variables of value 5
now, when the problem comes to the lambda:
auto f_1_0 = []()->int{return 5;};
std::function<int(void)> f_1_1 = []()->int{return 5;};
SomeType f_2 = []()->int{return 5;}; // what's the SomeType here?
Each lambda expression has its own unique type.
Here the expressions f_1 and f2 have different types.
auto f_1 = []()->int {return 5; };
auto f_2 = []()->int {return 5; };
Assigning f_2 = f_1 is illegal.
The standard says the types are "unnamed." In practice, the compiler probably makes up a new, hiiden typename for each lambda. Visual C++17 gave them the following names.
classmain::<lambda_7e9d7fb093569d78a8c871761cbb39d7>
classmain::<lambda_8f061a3967cd210147d6a4978ab6e125>
Not very useful information.
The standard says that the type of the lambda is unnamed so the implementation creates a implementation defined name it uses similar to the other unnamed classes, structs enumc etc.
ISO C++: 5.1.2 Lambda expressions [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 — called the closure type — whose properties are described below.
The standard also says that the lambda 'behaves like a function' so you it could be used with the std::function template:
[Note: A closure object behaves like a function object (20.9).—end note]
And if you really want to have names for your can use the old-fashioned functors and do all the work the compiler do for you with the lambdas.
in some cases you can use function pointers (using mvcpp, 0x17):
auto usingAuto = []() {
cout << "autoMagick" << endl;
};
void(*pureCpp)() = []() {
cout << "pureCpp" << endl;
};
//pureCpp = usingAuto; //you can even assing function pointers from lambdas
//usingAuto = pureCpp; //error
pureCpp();
usingAuto();
Related
Google's C++ Style Guide at some point states:
There are several contexts in which C++ allows (or even requires) types to be deduced by the compiler.
What are some examples of mandatory type deduction?
A simple example is initialisation of a lambda variable. The type of the lambda is anonymous, therefore it cannot be named explicitly and must be deduced:
auto var = [capture]{};
Another example:
struct {
int x, y;
} g_xy;
Here g_xy is a global variable of unnamed type. If you try to return it for example you have to let the compiler deduce the return type of the function because you cannot name it:
auto foo()
{
return g_xy;
}
Although possible unnamed types (except lamdas) are rarely useful and used.
The style guide gives several examples where the compiler does automatic type deduction. The most obvious case is whenever you use the auto keyword, introduced with C++11. auto is a placeholder for an actual type. Whenever you use auto the compiler will deduce the type from: the type of expression used to intialise a variable; the trailing type or type of return expression of a function.
Normally you would declare a variable like this:
int i = 0;
where you specify the type int for the variable i. However, in modern C++ you could declare variables without specifying their type and the compiler will deduce their types automatically:
auto a = 42; // a is an int
auto& b = a; // b is an int&
auto c = b; // c is an int
auto d{42}; // d is an int, not a std::initializer_list<int>
auto v = {1, 2, 3}; //v is a std::initializer_list<int>
Other examples include a named lambda function:
auto lower = [] (const char c) { return tolower(c); };
and in C++14 onward, a generic lambda where both the return type and lambda parameters can be auto:
auto add = [](const auto a, const auto b) { return a + b; }
One thing to note is that auto is a placeholder for type, not for const, volatile or reference specifers.
Some advantages of using auto include:
variable is always initialised
ensure the correct type is used without any implicit conversion
less typing and concern for actual type
And yet another example - type of generic lambdas with auto arguments can not be specified.
auto lam = [](auto v) { }
There is no way to specify type of v in invocation of lambda.
I had a perception that, type of a lambda is a function pointer. When I performed following test, I found it to be wrong (demo).
#define LAMBDA [] (int i) -> long { return 0; }
int main ()
{
long (*pFptr)(int) = LAMBDA; // ok
auto pAuto = LAMBDA; // ok
assert(typeid(pFptr) == typeid(pAuto)); // assertion fails !
}
Is above code missing any point? If not then, what is the typeof a lambda expression when deduced with auto keyword ?
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.
It is a unique unnamed structure that overloads the function call operator. Every instance of a lambda introduces a new type.
In the special case of a non-capturing lambda, the structure in addition has an implicit conversion to a function pointer.
[C++11: 5.1.2/3]: The type of the lambda-expression (which is also the type of the closure object) is a unique, unnamed non-union class type — called the closure type — whose properties are described below. This class type is not an aggregate (8.5.1). The closure type is declared in the smallest block scope, class scope, or namespace scope that contains the corresponding lambda-expression. [..]
The clause goes on to list varying properties of this type. Here are some highlights:
[C++11: 5.1.2/5]: The closure type for a lambda-expression has a public inline function call operator (13.5.4) whose parameters and return type are described by the lambda-expression’s parameter-declaration-clause and trailing-return-type respectively. [..]
[C++11: 5.1.2/6]: The closure type for a lambda-expression with no lambda-capture has a public non-virtual non-explicit const conversion function to pointer to function having the same parameter and return types as the closure type’s function call operator. The value returned by this conversion function shall be the address of a function that, when invoked, has the same effect as invoking the closure type’s function call operator.
The consequence of this final passage is that, if you used a conversion, you would be able to assign LAMBDA to pFptr.
#include <iostream>
#include <typeinfo>
#define LAMBDA [] (int i)->long { return 0l; }
int main ()
{
long (*pFptr)(int) = LAMBDA; // ok
auto pAuto = LAMBDA; // ok
std::cout<<typeid( *pAuto ).name() << std::endl;
std::cout<<typeid( *pFptr ).name() << std::endl;
std::cout<<typeid( pAuto ).name() << std::endl;
std::cout<<typeid( pFptr ).name() << std::endl;
}
The function types are indeed same, but the lambda introduces new type (like a functor).
It should also note that lambda is convertible to function pointer. However typeid<> returns a non-trvial object which should differ from lambda to generic function pointer. So the test for typeid<> is not a valid assumption. In general C++11 do not want us to worry about type specification, all that matter if a given type is convertible to a target type.
A practical solution from How can I store a boost::bind object as a class member?, try boost::function<void(int)> or std::function<void(int)>.
To further improve jalf's answer
A lambda which captures no variables (nothing inside the []'s) can be converted into a function pointer
for example:
typedef int (*Foo)(int a);
auto bar = [](int a){
return a;
};
int tmp = 1;
auto bar2 = [tmp](int a){
return a+tmp;
};
Foo foo = bar; // this is ok
Foo foo2 = bar2; // this gives C/C++(413)
This might work:
h1 {
font-size:20px;
}
h2{
font-size:18px;
}
p {
font-size: 16px;
}
exmp{
font-size:16px;
color:#000077;
/*font-style: oblique;*/
font-family: Lucida Console;
}
<h1>If you truly insist in defining a datatype other then auto for your lambda variable then I would recommend the following</h1>
<h2>Step 1: </h2>
<p>Typedef a function pointer</p>
<exmp> typedef void(*FuncPointerType)();</exmp>
<p>Note the empty parentheses, this will need to be the same as the arguments later of your lambda <br> Now create a function pointer as you would normaly do.</p>
<exmp>/void (**MyFunction)() = new FuncPointerType([](){});</exmp>
<p>Note that the you will have to go and manually delete the pointer as it is created on the heap<br>Finally call the function pointer, it can be called one of 2 ways:</p>
<exmp>(*(*MyFunction))();</exmp>
<p>OR</p>
<exmp>(*MyFunction)();</exmp>
<p>Note the importance that it should be returnd for a function pointer pointer to just a function pointer.</p>
I am working with the memory of some lambdas in C++, but I am a bit puzzled by their size.
Here is my test code:
#include <iostream>
#include <string>
int main()
{
auto f = [](){ return 17; };
std::cout << f() << std::endl;
std::cout << &f << std::endl;
std::cout << sizeof(f) << std::endl;
}
The ouptut is:
17
0x7d90ba8f626f
1
This suggests that the size of my lambda is 1.
How is this possible?
Shouldn't the lambda be, at minimum, a pointer to its implementation?
The lambda in question actually has no state.
Examine:
struct lambda {
auto operator()() const { return 17; }
};
And if we had lambda f;, it is an empty class. Not only is the above lambda functionally similar to your lambda, it is (basically) how your lambda is implemented! (It also needs an implicit cast to function pointer operator, and the name lambda is going to be replaced with some compiler-generated pseudo-guid)
In C++, objects are not pointers. They are actual things. They only use up the space required to store the data in them. A pointer to an object can be larger than an object.
While you might think of that lambda as a pointer to a function, it isn't. You cannot reassign the auto f = [](){ return 17; }; to a different function or lambda!
auto f = [](){ return 17; };
f = [](){ return -42; };
the above is illegal. There is no room in f to store which function is going to be called -- that information is stored in the type of f, not in the value of f!
If you did this:
int(*f)() = [](){ return 17; };
or this:
std::function<int()> f = [](){ return 17; };
you are no longer storing the lambda directly. In both of these cases, f = [](){ return -42; } is legal -- so in these cases, we are storing which function we are invoking in the value of f. And sizeof(f) is no longer 1, but rather sizeof(int(*)()) or larger (basically, be pointer sized or larger, as you expect. std::function has a min size implied by the standard (they have to be able to store "inside themselves" callables up to a certain size) which is at least as large as a function pointer in practice).
In the int(*f)() case, you are storing a function pointer to a function that behaves as-if you called that lambda. This only works for stateless lambdas (ones with an empty [] capture list).
In the std::function<int()> f case, you are creating a type-erasure class std::function<int()> instance that (in this case) uses placement new to store a copy of the size-1 lambda in an internal buffer (and, if a larger lambda was passed in (with more state), would use heap allocation).
As a guess, something like these is probably what you think is going on. That a lambda is an object whose type is described by its signature. In C++, it was decided to make lambdas zero cost abstractions over the manual function object implementation. This lets you pass a lambda into a std algorithm (or similar) and have its contents be fully visible to the compiler when it instantiates the algorithm template. If a lambda had a type like std::function<void(int)>, its contents would not be fully visible, and a hand-crafted function object might be faster.
The goal of C++ standardization is high level programming with zero overhead over hand-crafted C code.
Now that you understand that your f is in fact stateless, there should be another question in your head: the lambda has no state. Why does it not size have 0?
There is the short answer.
All objects in C++ must have a minimium size of 1 under the standard, and two objects of the same type cannot have the same address. These are connected, because an array of type T will have the elements placed sizeof(T) apart.
Now, as it has no state, sometimes it can take up no space. This cannot happen when it is "alone", but in some contexts it can happen. std::tuple and similar library code exploits this fact. Here is how it works:
As a lambda is equivalent to a class with operator() overloaded, stateless lambdas (with a [] capture list) are all empty classes. They have sizeof of 1. In fact, if you inherit from them (which is allowed!), they will take up no space so long as it doesn't cause a same-type address collision. (This is known as the empty base optimization).
template<class T>
struct toy:T {
toy(toy const&)=default;
toy(toy &&)=default;
toy(T const&t):T(t) {}
toy(T &&t):T(std::move(t)) {}
int state = 0;
};
template<class Lambda>
toy<Lambda> make_toy( Lambda const& l ) { return {l}; }
the sizeof(make_toy( []{std::cout << "hello world!\n"; } )) is sizeof(int) (well, the above is illegal because you cannot create a lambda in a non-evaluated context: you have to create a named auto toy = make_toy(blah); then do sizeof(blah), but that is just noise). sizeof([]{std::cout << "hello world!\n"; }) is still 1 (similar qualifications).
If we create another toy type:
template<class T>
struct toy2:T {
toy2(toy2 const&)=default;
toy2(T const&t):T(t), t2(t) {}
T t2;
};
template<class Lambda>
toy2<Lambda> make_toy2( Lambda const& l ) { return {l}; }
this has two copies of the lambda. As they cannot share the same address, sizeof(toy2(some_lambda)) is 2!
A lambda is not a function pointer.
A lambda is an instance of a class. Your code is approximately equivalent to:
class f_lambda {
public:
auto operator() { return 17; }
};
f_lambda f;
std::cout << f() << std::endl;
std::cout << &f << std::endl;
std::cout << sizeof(f) << std::endl;
The internal class that represents a lambda has no class members, hence its sizeof() is 1 (it cannot be 0, for reasons adequately stated elsewhere).
If your lambda were to capture some variables, they'll be equivalent to class members, and your sizeof() will indicate accordingly.
Your compiler more or less translates the lambda to the following struct type:
struct _SomeInternalName {
int operator()() { return 17; }
};
int main()
{
_SomeInternalName f;
std::cout << f() << std::endl;
}
Since that struct has no non-static members, it has the same size as an empty struct, which is 1.
That changes as soon as you add a non-empty capture list to your lambda:
int i = 42;
auto f = [i]() { return i; };
Which will translate to
struct _SomeInternalName {
int i;
_SomeInternalName(int outer_i) : i(outer_i) {}
int operator()() { return i; }
};
int main()
{
int i = 42;
_SomeInternalName f(i);
std::cout << f() << std::endl;
}
Since the generated struct now needs to store a non-static int member for the capture, its size will grow to sizeof(int). The size will keep growing as you capture more stuff.
(Please take the struct analogy with a grain of salt. While it's a nice way to reason about how lambdas work internally, this is not a literal translation of what the compiler will do)
Shouldn't the lambda be, at mimumum, a pointer to its implementation?
Not necessarily. According to the standard, the size of the unique, unnamed class is implementation-defined. Excerpt from [expr.prim.lambda], C++14 (emphasis mine):
The type of the lambda-expression (which is also the type of the closure object) is a unique, unnamed nonunion class type — called the closure type — whose properties are described below.
[ ... ]
An implementation may define the closure type differently from what is described below provided this does not alter the observable behavior of the program other than by changing:
— the size and/or alignment of the closure type,
— whether the closure type is trivially copyable (Clause 9),
— whether the closure type is a standard-layout class (Clause 9), or
— whether the closure type is a POD class (Clause 9)
In your case -- for the compiler you use -- you get a size of 1, which doesn't mean it's fixed. It can vary between different compiler implementations.
From http://en.cppreference.com/w/cpp/language/lambda:
The lambda expression constructs an unnamed prvalue 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.
If the lambda-expression captures anything by copy (either implicitly with capture clause [=] or explicitly with a capture that does not include the character &, e.g. [a, b, c]), the closure type includes unnamed non-static data members, declared in unspecified order, that hold copies of all entities that were so captured.
For the entities that are captured by reference (with the default capture [&] or when using the character &, e.g. [&a, &b, &c]), it is unspecified if additional data members are declared in the closure type
From http://en.cppreference.com/w/cpp/language/sizeof
When applied to an empty class type, always returns 1.
I had a perception that, type of a lambda is a function pointer. When I performed following test, I found it to be wrong (demo).
#define LAMBDA [] (int i) -> long { return 0; }
int main ()
{
long (*pFptr)(int) = LAMBDA; // ok
auto pAuto = LAMBDA; // ok
assert(typeid(pFptr) == typeid(pAuto)); // assertion fails !
}
Is above code missing any point? If not then, what is the typeof a lambda expression when deduced with auto keyword ?
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.
It is a unique unnamed structure that overloads the function call operator. Every instance of a lambda introduces a new type.
In the special case of a non-capturing lambda, the structure in addition has an implicit conversion to a function pointer.
[C++11: 5.1.2/3]: The type of the lambda-expression (which is also the type of the closure object) is a unique, unnamed non-union class type — called the closure type — whose properties are described below. This class type is not an aggregate (8.5.1). The closure type is declared in the smallest block scope, class scope, or namespace scope that contains the corresponding lambda-expression. [..]
The clause goes on to list varying properties of this type. Here are some highlights:
[C++11: 5.1.2/5]: The closure type for a lambda-expression has a public inline function call operator (13.5.4) whose parameters and return type are described by the lambda-expression’s parameter-declaration-clause and trailing-return-type respectively. [..]
[C++11: 5.1.2/6]: The closure type for a lambda-expression with no lambda-capture has a public non-virtual non-explicit const conversion function to pointer to function having the same parameter and return types as the closure type’s function call operator. The value returned by this conversion function shall be the address of a function that, when invoked, has the same effect as invoking the closure type’s function call operator.
The consequence of this final passage is that, if you used a conversion, you would be able to assign LAMBDA to pFptr.
#include <iostream>
#include <typeinfo>
#define LAMBDA [] (int i)->long { return 0l; }
int main ()
{
long (*pFptr)(int) = LAMBDA; // ok
auto pAuto = LAMBDA; // ok
std::cout<<typeid( *pAuto ).name() << std::endl;
std::cout<<typeid( *pFptr ).name() << std::endl;
std::cout<<typeid( pAuto ).name() << std::endl;
std::cout<<typeid( pFptr ).name() << std::endl;
}
The function types are indeed same, but the lambda introduces new type (like a functor).
It should also note that lambda is convertible to function pointer. However typeid<> returns a non-trvial object which should differ from lambda to generic function pointer. So the test for typeid<> is not a valid assumption. In general C++11 do not want us to worry about type specification, all that matter if a given type is convertible to a target type.
A practical solution from How can I store a boost::bind object as a class member?, try boost::function<void(int)> or std::function<void(int)>.
To further improve jalf's answer
A lambda which captures no variables (nothing inside the []'s) can be converted into a function pointer
for example:
typedef int (*Foo)(int a);
auto bar = [](int a){
return a;
};
int tmp = 1;
auto bar2 = [tmp](int a){
return a+tmp;
};
Foo foo = bar; // this is ok
Foo foo2 = bar2; // this gives C/C++(413)
This might work:
h1 {
font-size:20px;
}
h2{
font-size:18px;
}
p {
font-size: 16px;
}
exmp{
font-size:16px;
color:#000077;
/*font-style: oblique;*/
font-family: Lucida Console;
}
<h1>If you truly insist in defining a datatype other then auto for your lambda variable then I would recommend the following</h1>
<h2>Step 1: </h2>
<p>Typedef a function pointer</p>
<exmp> typedef void(*FuncPointerType)();</exmp>
<p>Note the empty parentheses, this will need to be the same as the arguments later of your lambda <br> Now create a function pointer as you would normaly do.</p>
<exmp>/void (**MyFunction)() = new FuncPointerType([](){});</exmp>
<p>Note that the you will have to go and manually delete the pointer as it is created on the heap<br>Finally call the function pointer, it can be called one of 2 ways:</p>
<exmp>(*(*MyFunction))();</exmp>
<p>OR</p>
<exmp>(*MyFunction)();</exmp>
<p>Note the importance that it should be returnd for a function pointer pointer to just a function pointer.</p>
From all the material I used to learn C++, auto has always been a weird storage duration specifier that didn't serve any purpose. But just recently, I encountered code that used it as a type name in and of itself. Out of curiosity I tried it, and it assumes the type of whatever I happen to assign to it!
Suddenly STL iterators and, well, anything at all that uses templates is 10 fold easier to write. It feels like I'm using a 'fun' language like Python.
Where has this keyword been my whole life? Will you dash my dreams by saying it's exclusive to visual studio or not portable?
auto was a keyword that C++ "inherited" from C that had been there nearly forever, but virtually never used because there were only two possible conditions: either it wasn't allowed, or else it was assumed by default.
The use of auto to mean a deduced type was new with C++11.
At the same time, auto x = initializer deduces the type of x from the type of initializer the same way as template type deduction works for function templates. Consider a function template like this:
template<class T>
int whatever(T t) {
// point A
};
At point A, a type has been assigned to T based on the value passed for the parameter to whatever. When you do auto x = initializer;, the same type deduction is used to determine the type for x from the type of initializer that's used to initialize it.
This means that most of the type deduction mechanics a compiler needs to implement auto were already present and used for templates on any compiler that even sort of attempted to implement C++98/03. As such, adding support for auto was apparently fairly easy for essentially all the compiler teams--it was added quite quickly, and there seem to have been few bugs related to it either.
When this answer was originally written (in 2011, before the ink was dry on the C++ 11 standard) auto was already quite portable. Nowadays, it's thoroughly portable among all the mainstream compilers. The only obvious reasons to avoid it would be if you need to write code that's compatible with a C compiler, or you have a specific need to target some niche compiler that you know doesn't support it (e.g., a few people still write code for MS-DOS using compilers from Borland, Watcom, etc., that haven't seen significant upgrades in decades). If you're using a reasonably current version of any of the mainstream compilers, there's no reason to avoid it at all though.
More recent revisions of the standard have added a few new places that auto can be used. Starting with C++14, you can use auto for the type of a parameter to a lambda:
[](auto s) { return s + 1; }
This does essentially the same thing as the example above--even though it doesn't explicitly use template syntax, this is basically a template that deduces the type of the parameter, and instantiates the template over that type.
That was convenient and useful enough that in C++20, the same capability was added for normal functions, not just lambdas.
But, just as before all of this really comes down to using the same basic type deduction mechanism as we've had for function templates since C++98. auto allows that to be used in more places, and more conveniently, but the underlying heavy lifting remains the same.
It's just taking a generally useless keyword and giving it a new, better functionality. It's standard in C++11, and most C++ compilers with even some C++11 support will support it.
For variables, specifies that the type of the variable that is being declared will be automatically deduced from its initializer. For functions, specifies that the return type is a trailing return type or will be deduced from its return statements (since C++14).
Syntax
auto variable initializer (1) (since C++11)
auto function -> return type (2) (since C++11)
auto function (3) (since C++14)
decltype(auto) variable initializer (4) (since C++14)
decltype(auto) function (5) (since C++14)
auto :: (6) (concepts TS)
cv(optional) auto ref(optional) parameter (7) (since C++14)
Explanation
When declaring variables in block scope, in namespace scope, in initialization statements of for loops, etc., the keyword auto may be used as the type specifier.
Once the type of the initializer has been determined, the compiler determines the type that will replace the keyword auto using the rules for template argument deduction from a function call (see template argument deduction#Other contexts for details). The keyword auto may be accompanied by modifiers, such as const or &, which will participate in the type deduction. For example, given const auto& i = expr;, the type of i is exactly the type of the argument u in an imaginary template template<class U> void f(const U& u) if the function call f(expr) was compiled. Therefore, auto&& may be deduced either as an lvalue reference or rvalue reference according to the initializer, which is used in range-based for loop.
If auto is used to declare multiple variables, the deduced types must match. For example, the declaration auto i = 0, d = 0.0; is ill-formed, while the declaration auto i = 0, *p = &i; is well-formed and the auto is deduced as int.
In a function declaration that uses the trailing return type syntax, the keyword auto does not perform automatic type detection. It only serves as a part of the syntax.
In a function declaration that does not use the trailing return type syntax, the keyword auto indicates that the return type will be deduced from the operand of its return statement using the rules for template argument deduction.
If the declared type of the variable is decltype(auto), the keyword auto is replaced with the expression (or expression list) of its initializer, and the actual type is deduced using the rules for decltype.
If the return type of the function is declared decltype(auto), the keyword auto is replaced with the operand of its return statement, and the actual return type is deduced using the rules for decltype.
A nested-name-specifier of the form auto:: is a placeholder that is replaced by a class or enumeration type following the rules for constrained type placeholder deduction.
A parameter declaration in a lambda expression. (since C++14) A function parameter declaration. (concepts TS)
Notes
Until C++11, auto had the semantic of a storage duration specifier.
Mixing auto variables and functions in one declaration, as in auto f() -> int, i = 0; is not allowed.
For more info : http://en.cppreference.com/w/cpp/language/auto
This functionality hasn't been there your whole life. It's been supported in Visual Studio since the 2010 version. It's a new C++11 feature, so it's not exclusive to Visual Studio and is/will be portable. Most compilers support it already.
The auto keyword is an important and frequently used keyword for C ++.When initializing a variable, auto keyword is used for type inference(also called type deduction).
There are 3 different rules regarding the auto keyword.
First Rule
auto x = expr; ----> No pointer or reference, only variable name. In this case, const and reference are ignored.
int y = 10;
int& r = y;
auto x = r; // The type of variable x is int. (Reference Ignored)
const int y = 10;
auto x = y; // The type of variable x is int. (Const Ignored)
int y = 10;
const int& r = y;
auto x = r; // The type of variable x is int. (Both const and reference Ignored)
const int a[10] = {};
auto x = a; // x is const int *. (Array to pointer conversion)
Note : When the name defined by auto is given a value with the name of a function,
the type inference will be done as a function pointer.
Second Rule
auto& y = expr; or auto* y = expr; ----> Reference or pointer after auto keyword.
Warning : const is not ignored in this rule !!! .
int y = 10;
auto& x = y; // The type of variable x is int&.
Warning : In this rule, array to pointer conversion (array decay) does not occur !!!.
auto& x = "hello"; // The type of variable x is const char [6].
static int x = 10;
auto y = x; // The variable y is not static.Because the static keyword is not a type. specifier
// The type of variable x is int.
Third Rule
auto&& z = expr; ----> This is not a Rvalue reference.
Warning : If the type inference is in question and the && token is used, the names
introduced like this are called "Forwarding Reference" (also called Universal Reference).
auto&& r1 = x; // The type of variable r1 is int&.Because x is Lvalue expression.
auto&& r2 = x+y; // The type of variable r2 is int&&.Because x+y is PRvalue expression.
The auto keyword specifies that the type of the variable that is being declared will be automatically deducted from its initializer. In case of functions, if their return type is auto then that will be evaluated by return type expression at runtime.
It can be very useful when we have to use the iterator. For e.g. for below code we can simply use the "auto" instead of writing the whole iterator syntax .
int main()
{
// Initialize set
set<int> s;
s.insert(1);
s.insert(4);
s.insert(2);
s.insert(5);
s.insert(3);
// iterator pointing to
// position where 2 is
auto pos = s.find(3);
// prints the set elements
cout << "The set elements after 3 are: ";
for (auto it = pos; it != s.end(); it++)
cout << *it << " ";
return 0;
}
This is how we can use "auto" keyword
It's not going anywhere ... it's a new standard C++ feature in the implementation of C++11. That being said, while it's a wonderful tool for simplifying object declarations as well as cleaning up the syntax for certain call-paradigms (i.e., range-based for-loops), don't over-use/abuse it :-)
It's Magic is it's ability to reduce having to write code for every Variable Type passed into specific functions. Consider a Python similar print() function in it's C base.
#include <iostream>
#include <string>
#include <array>
using namespace std;
void print(auto arg) {
cout<<arg<<" ";
}
int main()
{
string f = "String";//tok assigned
int x = 998;
double a = 4.785;
string b = "C++ Auto !";
//In an opt-code ASCII token stream would be iterated from tok's as:
print(a);
print(b);
print(x);
print(f);
}