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!
Oldest comments (4)
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! 😊
And remember that
constis a really good friend ofauto. Together, they are a perfect couple for modern C++ ^^Except that doesn't always mean what you think it means. If you originally did:
then the type of
iisunsigned(obviously); but if you change that toautoas above, then the type ofibecomesintbecause0is anintliteral. 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
forloops weren't a thing yet. (Even if they were, it's still incorrect since you're missing::const_iterator.) Range-basedforloops were addd to C++ at the same time asautoin C++11, so your "older standards" code should have been: