skip to content
Mehdi Mehdikhani
Table of Contents

The auto keyword is probably the C++11 feature I use most. It lets the compiler figure out types for you, making code cleaner and more maintainable.

What auto Actually Does

auto tells the compiler to deduce the type from the initializer:

auto x = 42; // int
auto y = 3.14; // double
auto z = "hello"; // const char*

The compiler looks at the right side and figures out what type the variable should be.

Why This Is Useful

Before auto, long type names made code verbose and fragile:

// The old way - verbose and error-prone
std::map<std::string, std::vector<int>>::iterator it = myMap.begin();
// With auto - clean and maintainable
auto it = myMap.begin();

If I change myMap’s type later, the auto version keeps working but the explicit type breaks.

When I Actually Use auto

Most of the time, I use auto in these situations:

  1. Iterator declarations: The most obvious win:
std::vector<std::string> names = {"Alice", "Bob", "Charlie"};
for (auto it = names.begin(); it != names.end(); ++it) {
std::cout << *it << std::endl;
}
// Even better with range-based for
for (const auto& name : names) {
std::cout << name << std::endl;
}
  1. Complex template types: When the type name is unwieldy:
auto func = std::bind(&MyClass::method, this, std::placeholders::_1);
auto lambda = [](int x) { return x * 2; };
auto future = std::async(std::launch::async, some_function);
  1. Template function returns: When I can’t know the return type:
template<typename T, typename U>
auto multiply(T a, U b) -> decltype(a * b) { // C++11 syntax
return a * b;
}
// C++14 makes it even simpler
template<typename T, typename U>
auto multiply(T a, U b) {
return a * b;
}
  1. Range-based for loops: Always use auto here:
std::map<std::string, int> scores;
for (const auto& pair : scores) { // pair is std::pair<const std::string, int>
std::cout << pair.first << ": " << pair.second << std::endl;
}

The Gotchas

auto doesn’t always do what you expect:

auto x = 3.14f; // float, not double
auto y = {1, 2, 3}; // std::initializer_list<int> in C++11
auto z = "hello"; // const char*, not std::string

Reference and const qualifiers are dropped:

const int& get_value();
auto x = get_value(); // int, not const int&
const auto& y = get_value(); // const int& - need to be explicit

AAA: Almost Always Auto

Some people follow the “Almost Always Auto” rule:

auto x = int{42}; // Instead of: int x = 42;
auto y = std::string{"hi"}; // Instead of: std::string y = "hi";

I’m not that extreme, but I do use auto whenever the type is obvious from context or when it makes the code more readable.

C++14 and Beyond

C++14 added more auto features:

// Function parameters (C++20)
auto add = [](auto a, auto b) { return a + b; };
// Return type deduction (C++14)
auto get_name() {
return std::string{"John"}; // Return type deduced as std::string
}

The Rule I Follow

Use auto when:

  • The type is obvious from the right side
  • The exact type doesn’t matter (iterators, lambdas)
  • It makes the code more maintainable
  • Working with templates where types are complex

Don’t use auto when:

  • The type isn’t clear from context
  • You need specific type conversions
  • It hurts readability

auto makes C++ feel less verbose and more modern. Once you start using it, going back to explicit types feels tedious.