In modern C++, you write
auto auto(auto auto) { auto; }
and the compiler infers the rest
Ok, it's not that easy, but I promise that using auto
does indeed feel like magic. Let's go with the first article with actual content of the Learning modern C++
series!
The auto
keyword is used to let the compiler infer the type of a variable automatically from its initial value instead of having to explicitly declare it. (Bonus: forget about uninitialized variables!) For instance:
// Older standards
int i = 0;
// Modern C++
auto i = 0;
At first, this may not seem like a huge deal, but let's see another example. If we have a getMatrix
function that returns a std::vector<std::vector<int>>
type, we can easily print all its elements with a range-based for
loop (if you don't know what a range-based for
loop is, you'll love the next article of this series!). In this example, you'll see how auto
starts to shine a bit more:
// Older standards
std::vector<std::vector<int>> matrix = getMatrix();
for (std::vector<int> row : matrix) {
for (int element : row) {
std::cout << element << std::endl;
}
}
// Modern C++
auto matrix = getMatrix();
for (auto row : matrix) {
for (auto element : row) {
std::cout << element << std::endl;
}
}
Hey, isn't that cool? 😎 And it gets even better! What would happen if the getMatrix
function was changed to return a std::vector<std::vector<double>>
type instead? With older C++ standards, we would have to adapt our code in order for it to work again, but using the modern C++ auto
keyword we wouldn't need to touch anything!
Of course, this gets even more meaningful in real-world examples, but I think the ones presented should be enough to at least spark some interest.
auto
can also be used in function declarations, although I must admit that I haven't committed to it (yet?). The syntax is:
// Older standards
int getIntParameter(int parameter) { return parameter; }
// Modern C++
auto getIntParameter(int parameter) -> int { return parameter; }
However, it can be very useful when used in conjunction with the decltype
specifier (which inspects the declared type of a varibale):
template <typename T, typename U>
auto sum(T t, U u) -> decltype(t + u) { return t + u; }
Note that in the example above we don't know the types t
and u
, but we don't even need it! We could call the function like:
auto x = sum(1, 1); // (int) 2
auto y = sum(1, 0.14); // (double) 1.14
auto pi = sum(x, y); // (double) 3.14
auto tau = sum(pi, pi); // (double) 6.28
And everything will work wonderfully 🎉
That's probably enough for the post, let me know what you think of it on the comments section below! Reacting to and sharing the post is also appreciated 😊 And, as always, thanks for reading!
Top comments (4)
Except that doesn't always mean what you think it means. If you originally did:
then the type of
i
isunsigned
(obviously); but if you change that toauto
as above, then the type ofi
becomesint
because0
is anint
literal. If you want it to stayunsigned
, then you have to be explicit:You have the same problem for
short
,long
,long long
, and their unsigned variants.This is incorrect. In the "older standards" (C++03 and earlier), range-based
for
loops weren't a thing yet. (Even if they were, it's still incorrect since you're missing::const_iterator
.) Range-basedfor
loops were addd to C++ at the same time asauto
in C++11, so your "older standards" code should have been:And remember that
const
is a really good friend ofauto
. Together, they are a perfect couple for modern C++ ^^Nice article, thanks! Here is a great article by Herb Sutter, in case you want to dive even deeper.
Thanks for the comment and the reference Sandor, it's much appreciated! 😊