C++学习笔记-auto关键字

auto关键字让编译器自动推导变量的类型,可以简化代码并提高可读性。Cherno建议谨慎使用auto,在类型比较长的复杂情况时才考虑使用auto。

auto的基本使用

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#include <iostream>
#include <vector>
#include <string>

int main()
{
    // 基本类型的auto推导
    auto a = 5;        // int
    auto b = "Hello";  // const char*
    auto c = 5.5f;     // float
    auto d = 5.5;      // double
    auto e = true;     // bool
    
    std::cout << "a = " << a << " (int)" << std::endl;
    std::cout << "b = " << b << " (const char*)" << std::endl;
    std::cout << "c = " << c << " (float)" << std::endl;
    std::cout << "d = " << d << " (double)" << std::endl;
    std::cout << "e = " << e << " (bool)" << std::endl;
    
    // 注意:对于简单类型,不建议使用auto
    // 更好的做法是明确指定类型
    int x = 5;
    float y = 5.5f;
    bool z = true;
    
    return 0;
}

auto在迭代器中的应用

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
#include <iostream>
#include <vector>
#include <string>
#include <map>

int main()
{
    std::vector<std::string> strings;
    strings.push_back("Apple");
    strings.push_back("Orange");
    strings.push_back("Banana");
    
    // 传统方式:类型名很长
    for (std::vector<std::string>::iterator it = strings.begin(); it != strings.end(); ++it)
    {
        std::cout << *it << std::endl;
    }
    
    // 使用auto简化:Cherno推荐使用auto的地方之一
    for (auto it = strings.begin(); it != strings.end(); ++it)
    {
        std::cout << *it << std::endl;
    }
    
    // 更现代的方式:范围for循环
    for (const auto& str : strings)
    {
        std::cout << str << std::endl;
    }
    
    // 复杂容器的迭代器
    std::map<std::string, int> scores;
    scores["Alice"] = 95;
    scores["Bob"] = 87;
    scores["Charlie"] = 92;
    
    // 传统方式:非常冗长
    for (std::map<std::string, int>::const_iterator it = scores.begin(); it != scores.end(); ++it)
    {
        std::cout << it->first << ": " << it->second << std::endl;
    }
    
    // 使用auto:简洁明了
    for (auto it = scores.begin(); it != scores.end(); ++it)
    {
        std::cout << it->first << ": " << it->second << std::endl;
    }
    
    // 范围for循环配合auto
    for (const auto& pair : scores)
    {
        std::cout << pair.first << ": " << pair.second << std::endl;
    }
    
    return 0;
}

auto与函数返回值

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
#include <iostream>
#include <vector>
#include <string>

// 函数返回复杂类型
std::vector<std::string> GetStringVector()
{
    return {"Hello", "World", "C++"};
}

std::map<std::string, int> GetScoreMap()
{
    return {{"Alice", 95}, {"Bob", 87}, {"Charlie", 92}};
}

// auto作为函数返回类型(C++14)
auto CreateVector()
{
    return std::vector<int>{1, 2, 3, 4, 5};
}

auto CalculateSum(int a, int b)
{
    return a + b;  // 返回类型自动推导为int
}

// 尾置返回类型(C++11)
template<typename T, typename U>
auto Add(T a, U b) -> decltype(a + b)
{
    return a + b;
}

int main()
{
    // 接收复杂返回类型
    auto strings = GetStringVector();  // std::vector<std::string>
    auto scores = GetScoreMap();       // std::map<std::string, int>
    
    std::cout << "Strings size: " << strings.size() << std::endl;
    std::cout << "Scores size: " << scores.size() << std::endl;
    
    // 使用auto接收函数返回值
    auto numbers = CreateVector();
    auto sum = CalculateSum(10, 20);
    
    std::cout << "Numbers size: " << numbers.size() << std::endl;
    std::cout << "Sum: " << sum << std::endl;
    
    // 混合类型运算
    auto result = Add(5, 3.14);  // double
    std::cout << "Mixed result: " << result << std::endl;
    
    return 0;
}

auto的修饰符

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
#include <iostream>
#include <vector>

int main()
{
    std::vector<int> numbers = {1, 2, 3, 4, 5};
    
    // auto会去掉引用和const
    const int& ref = numbers[0];
    auto a = ref;        // int,不是const int&
    auto& b = ref;       // const int&
    const auto& c = ref; // const int&
    
    // auto与指针
    int value = 42;
    int* ptr = &value;
    auto d = ptr;        // int*
    auto* e = ptr;       // int*
    auto& f = ptr;       // int*&
    
    // auto与数组
    int arr[5] = {1, 2, 3, 4, 5};
    auto g = arr;        // int*,数组退化为指针
    auto& h = arr;       // int(&)[5],数组引用
    
    std::cout << "a = " << a << std::endl;
    std::cout << "b = " << b << std::endl;
    std::cout << "c = " << c << std::endl;
    std::cout << "*d = " << *d << std::endl;
    std::cout << "*e = " << *e << std::endl;
    std::cout << "*f = " << *f << std::endl;
    
    return 0;
}

auto在lambda表达式中的应用

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
#include <iostream>
#include <vector>
#include <algorithm>
#include <functional>

int main()
{
    std::vector<int> numbers = {5, 2, 8, 1, 9, 3};
    
    // 存储lambda表达式
    auto lambda = [](int a, int b) { return a < b; };
    
    // 使用lambda排序
    std::sort(numbers.begin(), numbers.end(), lambda);
    
    std::cout << "Sorted numbers: ";
    for (int num : numbers)
    {
        std::cout << num << " ";
    }
    std::cout << std::endl;
    
    // 复杂的lambda
    auto complexLambda = [](const std::string& str) -> bool {
        return str.length() > 3;
    };
    
    std::vector<std::string> words = {"cat", "dog", "elephant", "ant", "butterfly"};
    
    // 使用std::function存储(如果需要)
    std::function<bool(const std::string&)> filter = complexLambda;
    
    std::cout << "Words longer than 3 characters: ";
    for (const auto& word : words)
    {
        if (filter(word))
        {
            std::cout << word << " ";
        }
    }
    std::cout << std::endl;
    
    // auto在算法中的应用
    auto found = std::find_if(words.begin(), words.end(), 
                             [](const std::string& word) { return word[0] == 'e'; });
    
    if (found != words.end())
    {
        std::cout << "Found word starting with 'e': " << *found << std::endl;
    }
    
    return 0;
}

auto的最佳实践

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
#include <iostream>
#include <vector>
#include <map>
#include <memory>

class MyClass
{
public:
    void DoSomething() { std::cout << "MyClass doing something" << std::endl; }
};

int main()
{
    std::cout << "=== Auto Best Practices ===" << std::endl;
    
    // 1. 推荐使用auto的情况:复杂类型名
    std::map<std::string, std::vector<int>> complexMap;
    complexMap["numbers"] = {1, 2, 3, 4, 5};
    
    // 好:使用auto避免冗长的类型名
    for (const auto& pair : complexMap)
    {
        std::cout << "Key: " << pair.first << ", Values: ";
        for (const auto& value : pair.second)
        {
            std::cout << value << " ";
        }
        std::cout << std::endl;
    }
    
    // 2. 推荐使用auto的情况:迭代器
    std::vector<std::unique_ptr<MyClass>> objects;
    objects.push_back(std::make_unique<MyClass>());
    objects.push_back(std::make_unique<MyClass>());
    
    // 好:迭代器类型很复杂
    for (auto it = objects.begin(); it != objects.end(); ++it)
    {
        (*it)->DoSomething();
    }
    
    // 3. 不推荐使用auto的情况:简单类型
    // 不好:类型不明确
    // auto x = 5;
    // auto y = 3.14f;
    
    // 好:类型明确
    int x = 5;
    float y = 3.14f;
    
    // 4. 推荐使用auto的情况:模板和泛型编程
    auto result = std::make_pair(42, "Hello");  // std::pair<int, const char*>
    std::cout << "Pair: " << result.first << ", " << result.second << std::endl;
    
    // 5. 注意auto的类型推导
    std::vector<bool> boolVector = {true, false, true};
    auto element = boolVector[0];  // 不是bool,而是std::vector<bool>::reference
    bool actualBool = boolVector[0];  // 明确指定类型
    
    std::cout << "Element type might not be what you expect" << std::endl;
    
    return 0;
}

auto与模板

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
#include <iostream>
#include <type_traits>

template<typename T>
void ProcessValue(T value)
{
    std::cout << "Processing value: " << value << std::endl;
    
    // 使用auto进行类型推导
    auto doubled = value * 2;
    std::cout << "Doubled: " << doubled << std::endl;
    
    // 检查类型
    if constexpr (std::is_integral_v<T>)
    {
        std::cout << "T is an integral type" << std::endl;
    }
    else if constexpr (std::is_floating_point_v<T>)
    {
        std::cout << "T is a floating point type" << std::endl;
    }
}

// 完美转发与auto
template<typename T>
auto ForwardValue(T&& value)
{
    std::cout << "Forwarding value" << std::endl;
    return std::forward<T>(value);
}

// decltype(auto)用于完美转发返回类型
template<typename Func, typename... Args>
decltype(auto) CallFunction(Func&& func, Args&&... args)
{
    std::cout << "Calling function" << std::endl;
    return std::forward<Func>(func)(std::forward<Args>(args)...);
}

int Square(int x)
{
    return x * x;
}

int main()
{
    ProcessValue(42);
    ProcessValue(3.14);
    ProcessValue("Hello");
    
    // 完美转发示例
    auto forwarded = ForwardValue(100);
    std::cout << "Forwarded value: " << forwarded << std::endl;
    
    // 函数调用包装
    auto result = CallFunction(Square, 5);
    std::cout << "Square result: " << result << std::endl;
    
    return 0;
}

总结

  1. auto的作用:让编译器自动推导变量类型,简化代码
  2. 推荐使用场景
    • 复杂的类型名(如长的模板类型)
    • 迭代器类型
    • lambda表达式
    • 模板和泛型编程中
  3. 不推荐使用场景
    • 简单类型(int、char等)
    • 需要明确类型的场合
  4. 注意事项
    • auto会去掉引用和const修饰符
    • 某些容器(如std::vector)的auto推导可能不符合预期
    • 要同时考虑代码的可读性和简洁性
  5. Cherno的建议:当类型比较长的复杂情况时时候可以考虑使用auto,简单类型就不要用了
updatedupdated2025-09-202025-09-20