Skip to content

Wiki

auto

About 14 min read

Existing English translations were reused. 2 current source blocks remain in Simplified Chinese, without triggering paid translation.

1.What problem does this section solve?

In C++ , many type names are long, hard to write, and easy to get wrong, for example:

std::map<std::string, std::vector<int>>::const_iterator it = m.begin();
std::shared_ptr<MyClass> ptr = std::make_shared<MyClass>();

autoLet the compiler automatically infer types for us, reducing verbose type declarations and making the code more concise and easier to maintain.

2.What is this feature?

autoThe keyword tells the compiler: "Please infer the type of this variable automatically based on the initialized value." It does not weaken type safety—the inferred type is already determined at compile time, so it remains strongly typed.

3.C++ Standard Edition

C++11 (basic usage), C++14 added auto as function return type deduction, C++17 added auto for use in structured bindings and similar scenarios.

4.Required header files

No additional header files are required.auto is a language keyword.

5.Basic syntax

auto 变量名 = 表达式;        // 编译器根据表达式推导类型
const auto 变量名 = 表达式;  // 推导后加 const
auto& 变量名 = 表达式;       // 推导为引用类型
const auto& 变量名 = 表达式; // 推导为只读引用类型

6.Common Usage

Usage Description Example
auto Deduce value type automatically (loses references and const) auto x = 42; → int
const auto Deduced as read-only type const auto s = "hello";
auto& Deduced as reference (can modify the original value) auto& x = vec[0];
const auto& Deduced as read-only reference (no copy, not modifiable) const auto& x = get_value();
auto* Deduced as pointer auto* p = &x;
decltype(auto) Perfect forwarding preserving references and cv qualifiers (C++14) decltype(auto) x = get_ref();

7.When to use which one

autoThe most easily misunderstood point is: it does not "automatically become the type you want," but rather infers according to fixed rules. This is especially true when encountering references,constor function return values, you should proactively write your intent clearly.

Scenario Recommended写法 Reason
Local variable type is obvious auto x = expr; Avoid repeating the type
Read-only traversal of large objects const auto& x Avoid copying while disallowing modification
Need to modify the original object auto& x Explicitly obtain a reference
Pointer that may be null auto* p = get(); Let readers see at a glance that this is a pointer
Function returns a reference and the reference must be preserved decltype(auto) auto The return value will lose the reference
The type itself carries business meaning Explicit type For example Meter distance = ... than auto distance is clearer

8.Example code

8.1.Example 1: Basic type inference

#include <iostream>
#include <string>

int main()
{
    auto n = 42;              // int
    auto d = 3.14;            // double
    auto c = 'A';             // char
    auto s = "hello";         // const char*
    auto str = std::string("world");  // std::string

    std::cout << "n = " << n << "\n";
    std::cout << "d = " << d << "\n";
    std::cout << "c = " << c << "\n";
    std::cout << "str = " << str << "\n";

    return 0;
}

Running result:

n = 42
d = 3.14
c = A
str = world

8.2.Example 2: Based on Example 1, the difference between auto& and const auto&

#include <iostream>

int main()
{
    int x = 10;

    auto a = x;         // a 是 int,拷贝了 x
    auto& b = x;        // b 是 int&,是 x 的引用
    const auto& c = x;  // c 是 const int&,只读引用

    a = 100;
    std::cout << "after a=100, x = " << x << "\n";  // x 不变

    b = 200;
    std::cout << "after b=200, x = " << x << "\n";  // x 变了

    // c = 300;  // ❌ 编译错误!c 是只读引用

    return 0;
}

Running result:

after a=100, x = 10
after b=200, x = 200

8.3.Example 3: Building on Example 2, use auto to simplify iterators and complex types

#include <iostream>
#include <vector>
#include <map>
#include <memory>
#include <string>

int main()
{
    std::vector<std::string> names = {"Alice", "Bob", "Charlie"};

    // 不用 auto 的写法(类型名很长)
    for (std::vector<std::string>::const_iterator it = names.begin();
         it != names.end(); ++it)
    {
        std::cout << *it << " ";
    }
    std::cout << "\n";

    // 用 auto 简化(同样清晰)
    for (auto it = names.begin(); it != names.end(); ++it)
    {
        std::cout << *it << " ";
    }
    std::cout << "\n";

    // 智能指针用 auto 简化
    auto ptr = std::make_shared<int>(42);
    std::cout << "*ptr = " << *ptr << "\n";

    return 0;
}

Running result:

Alice Bob Charlie 
Alice Bob Charlie 
*ptr = 42

8.4.Example 4: When using auto to iterate over a container, be careful about copy vs reference

#include <iostream>
#include <vector>
#include <string>

int main()
{
    std::vector<std::string> names = {"Alice", "Bob", "Charlie"};

    // ❌ 错误用法:auto 会拷贝每个元素(低效)
    std::cout << "auto (copies): ";
    for (auto s : names)
    {
        s = "X";  // 修改的是拷贝,不影响原容器
    }
    for (auto s : names)
    {
        std::cout << s << " ";
    }
    std::cout << "(unchanged)\n";

    // ✅ 正确用法:auto& 修改原容器中的元素
    for (auto& s : names)
    {
        s = "X";
    }
    std::cout << "auto& (references): ";
    for (auto s : names)
    {
        std::cout << s << " ";
    }
    std::cout << "(modified)\n";

    return 0;
}

Running result:

auto (copies): Alice Bob Charlie (unchanged)
auto& (references): X X X (modified)

8.5.Example 5: Building on Example 4, the difference between auto return values and decltype(auto) (pointers)

#include <iostream>

int global_score = 80;

int* score_ptr()
{
    return &global_score;
}

// auto 推导指针返回类型时,推导结果就是 int*(指针本身被拷贝,但指向不变)
auto read_ptr()
{
    return score_ptr();
}

// decltype(auto) 对非引用表达式,效果等同于 auto,结果同样是 int*
decltype(auto) borrow_ptr()
{
    return score_ptr();
}

int main()
{
    auto p1 = score_ptr();      // p1 是 int*,拷贝了"指针",但地址值相同
    *p1 = 90;
    std::cout << "after auto p1, *p1 = 90, global_score = " << global_score << "\n";

    int*& p_ref = score_ptr();  // 这里会报错!score_ptr() 是右值,不能绑定到 int*& 上
    // (此行仅作对比说明用,实际编译会失败,下方运行结果不包含它)

    auto p2 = read_ptr();       // p2 也是 int*,read_ptr 本身也按值返回指针
    *p2 = 100;
    std::cout << "after auto p2, *p2 = 100, global_score = " << global_score << "\n";

    decltype(auto) p3 = borrow_ptr(); // p3 仍是 int*,跟 auto 推导结果一样
    *p3 = 110;
    std::cout << "after decltype(auto) p3, *p3 = 110, global_score = " << global_score << "\n";

    return 0;
}

Running result:

after auto p1, *p1 = 90, global_score = 90
after auto p2, *p2 = 100, global_score = 100
after decltype(auto) p3, *p3 = 110, global_score = 110

8.6.Example 6: Building on Example 5, the difference between auto return values and decltype(auto) (references)

#include <iostream>

int global_score = 80;

int& score_ref()
{
    return global_score;
}

// auto 作为函数返回类型时,会按"值"返回,引用会被丢掉
auto read_score()
{
    return score_ref();
}

// decltype(auto) 会保留 score_ref() 的 int& 返回类型
decltype(auto) borrow_score()
{
    return score_ref();
}

int main()
{
    auto a = score_ref();       // a 是 int,拷贝
    a = 90;
    std::cout << "after auto a = 90, global_score = " << global_score << "\n";

    auto& b = score_ref();      // b 是 int&,引用
    b = 90;
    std::cout << "after auto& b = 90, global_score = " << global_score << "\n";

    auto c = read_score();      // c 是 int,read_score 本身也返回拷贝
    c = 100;
    std::cout << "after auto c = 100, global_score = " << global_score << "\n";

    decltype(auto) d = borrow_score(); // d 是 int&,仍然引用 global_score
    d = 100;
    std::cout << "after decltype(auto) d = 100, global_score = " << global_score << "\n";

    score_ref() = 110;          // 直接对函数调用结果赋值,score_ref() 本身是左值
    std::cout << "after score_ref() = 110, global_score = " << global_score << "\n";

    // read_score() = 120;      // 编译错误:read_score() 返回 int(按值),是右值,不能直接赋值

    return 0;
}

Running result:

after auto a = 90, global_score = 80
after auto& b = 90, global_score = 90
after auto c = 100, global_score = 90
after decltype(auto) d = 100, global_score = 100
after score_ref() = 110, global_score = 110
问题 示例 5(引用) 示例 6(指针)
score_ref() / score_ptr() 返回什么 int&(绑定到 global_score 本身) int*(一个保存 global_score 地址的值)
auto a = score_ref(); 拷贝的是什么 int 的值 → 和 global_score 脱钩 ——
auto p1 = score_ptr(); 拷贝的是什么 —— "指针变量"这个值(地址)→ 但地址指向的还是 global_score
修改 a / *p1 能否影响 global_score a = 90 不能 *p1 = 90 能
auto 经过函数包一层(read_score/read_ptr)后还能改到原变量吗 不能(引用性已丢失) 能(指针的指向关系从一开始就不依赖"引用性")
decltype(auto) 相比 auto 的意义 关键:保住了 int&,否则会退化成 int 拷贝 没有额外意义:函数返回的本来就是 int*(一个普通值),decltype(auto) 和 auto 推导结果完全一致

auto There is only one thing that is truly "lost":the referentiality of an expression (that is, "whether it is bound to an existing object").

  • For score_ref() (returning int&), referentiality is its entire value—once lost, a becomes a copy with no relation to the original variable. decltype(auto)'s role is to preserve this referentiality.

  • For score_ptr() (returning int*), it itself is not a reference but an ordinary value (even if this value happens to be an address).autoWhen deducing an ordinary value type, "reference loss" never occurs in the first place, so what is deduced is naturally int*, with no difference whatsoever from the result deduced by decltype(auto). What truly determines "whether the original variable can be modified" is never auto versus decltype(auto); rather, it is whether the value you copy still carries a "path" pointing to the original object:

  • Copying the int value — the path is broken, so it cannot be modified.

  • Copying int* (the address value) — the path is still there, and after dereferencing, it can still be modified.


9.Operation result

See the "run results" for each example above.

10.Key syntax explanation in the example

Example What was discussed Newly introduced syntax Why it is written this way Precautions
Example 1 Basic type deduction auto x = 表达式 The simplest case: the type is determined by the initializer String literals are deduced as const char*
Example 2 auto vs auto& vs const auto& auto&、const auto& auto loses references and top-level const, so auto& is needed to refer to the original variable Pay attention when iterating over container elements
Example 3 Simplifying complex types Use auto for iterators and smart pointers Use auto to keep readability when type names are too long auto does not weaken type safety; it just lets the compiler write it for you
Example 4 The copy pitfall when iterating with auto Range for + auto/auto& auto iterates over copied elements,auto& refers to elements To modify the original container, you must use auto&
Example 5 auto return type vs decltype(auto) auto function return,decltype(auto) When a function returns a reference, ordinary auto degrades to a value return decltype(auto) is powerful, but you also need to make sure it will not return a dangling reference

11.Common Errors

Error 1: assuming that auto can be automatically deduced as a reference

int x = 10;
auto y = x;
y = 20;  // x 不会变!y 是拷贝不是引用

Correct approach: to modify the original variable, use auto&.

错误 2:用 auto 声明函数参数

void func(auto x) { ... }  // C++20 之前是错误!(除非是泛型 lambda)

Correct approach: ordinary function parameters cannot use auto(C++20 is allowed, but that is template syntax).

Error 3:auto cannot be used in multi-variable declarations

auto x = 1, y = 3.14;  // ❌ 编译错误!推导类型不一致

Correct approach: declare each auto variable separately.

Error 4: Abusing auto makes business meaning disappear

auto timeout = 3000;  // 3000 是毫秒?秒?次数?

Correct approach: types or names should convey meaning. For example, std::chrono::milliseconds timeout{3000};, or at least write it as auto timeout_ms = 3000;.

12.Usage Recommendations

  1. Use auto wherever possibleto reduce repeated type declarations and make the code more concise.
  2. To iterate over containers, use const auto&(when no modification is needed) or auto&(when modification is needed), to avoid accidental copies.
  3. Where a reference is explicitly needed, write auto&: auto does not automatically deduce a reference.
  4. auto cannot fully replace explicit typesWhen the type is not obvious (such as when deduced from a function return value), writing the type explicitly may be clearer.
  5. decltype(auto) Use it only when you really want to preserve references: it is more precise and also makes dangling references easier to expose.

13.Summary

  • auto Let the compiler automatically deduce variable types, reducing verbose type declarations.
  • auto References and top-level const are dropped; to iterate over containers, use const auto& or auto&.
  • It is especially suitable for simplifying complex types such as iterators and smart pointers.
  • auto Function return values are returned by value by default; when reference semantics need to be preserved, use decltype(auto).
  • auto It is still strongly typed, and the type is determined at compile time.