Type Deduction(templates, auto, decltype)
Many of the following are excerpts from Scott Meyers - Effective Modern C++
Templates
1 |
|
It’s clear that f1
takes an lvalue reference of T1
, f2
takes an lvalue reference of const T2
.
1 |
|
For the last 3 examples, since param is passed by value, reserving const-ness of cx or rx does not make sense, since param is independent from cx or rx. Changing param has no effect on cx or rx.
Auto
auto, in most cases is an algorithmic transformation from template. For example auto x = 27
, fits into T5
, const auto cx = x
fits into T5
, const auto& rx = x
fits into T2
, auto&& rv = x
and auto&& rv = 7
fits into T4
, auto x = &lvalue
fits into T1
. You can view resolving auto as doing an equivalent template type deduction.
There is a case they differ.
1 |
|
When constructing an item with the brace, auto is a type of std::initializer_list<int>
. This type is used to access the values in the initialization list, which is a list of elements of type const T
. Thus values in the brace should be of the same type.
If you pass a brace initialized item to a function, it will be treated as std::initializer_list
, and normal template type deduction cannot solve it. For example:
1 |
|
In C++14, another point to notice that, if you use auto
as the return type, or use auto
in lambda parameter declarations, it will be treated as template type deductions, thus returning a braced initializer or passing that into lambdas won’t compile.
1 |
|
Using auto has many virtues, especially when the type is very complicated or not useful to be written out in the full form. However there is one case that auto may not do what you want, that is to use auto in declaring a proxy class, which often is not designed to live longer than a single statement. The book gives an example:
1 |
|
decltype
It reminds me of type()
in Python. At the end they do very similar things and in most cases do not give you surprises. One case it gives you surprise is when you pass a lvalue more complicated than a name, it will reports that type as T&
. For example,
1 |
|
Some usage of decltype
include: use decltype
to show return type of the function in the trailing return type syntax(->
) in C++11, and guard the real return/initialization type in C++14. For example,
1 |
|
Another example to guard the return value:
1 |
|
Why we might want to do that? Difference containers, such as std::string
, std::deque
, std::vector
, may return elements by value of by reference. In the case a reference is returned, since auto
uses the template type reduction, if we do not use decltype, the return value will strip the reference off.