Auto-type Deduction Rules

Auto-type deduction allows the compiler to deduce the type of a variable from its initializer.

Source code on C++ insights

1. Deduction with reference

If the initializer is a reference, the reference type is stripped, and auto deduces the underlying type. If you want auto to deduce a reference, you must explicitly use auto&.

source.cpp
1
2
3
4
int a1 = 3;
int& ref = a1;
auto b1 = ref; // int b1 = ref;
auto& c1 = ref; // int& c1 = ref;

2. Deduction with const

If the initializer is const, auto deduces the type without const unless explicitly specified.

source.cpp
1
2
3
const int a2 = 3;
auto b2 = a2; // int b2 = a2;
const auto c2 = a2; // const int c2 = a2;

In C++, const can appear in different context, and its role can be categorized as either top-level const or low-level const.

Top-level const applies to the object itself, indicating that the object itself cannot be modified.

example.cpp
1
2
const int x = 42;  // `x` is a `const int` (the value of `x` cannot be modified)
int* const ptr = &x; // `ptr` is a `const pointer` to `int` (the pointer itself cannot change, but the pointee can)

Low-level const applies to the type being referred to or pointed to. It means the value being referred to or pointed to cannot be modified.

example.cpp
1
2
const int* ptr = &x;   // `ptr` is a pointer to a `const int` (the value of the pointee cannot be modified)
const int* const cptr = &x; // `cptr2` is a `const pointer` to a `const int`, the left const is low-level const

It is important to note that:
Top-level const is ignored when using auto-type deduction unless explicitly specified. Low-level const is preserved during auto-type deduction.

example.cpp
1
2
3
4
const int a2 = 3;
const int* const d2 = &a2;
auto e2 = d2; // const int*
const auto f2 = d2; // const int* const

3. Deduction with pointers

If a pointer is involved, auto deduces the pointer type.

example.cpp
1
2
3
int a3 = 3;
int* p3 = &a3;
auto b3 = p3; // int*

4. Deduction with Arrays

For arrays, auto deduces to a pointer to the first element of the array. auto& deduces the array type.

example.cpp
1
2
3
int arr4[] = {1, 2, 3, 4};
auto a4 = arr4; // int*
auto& b4 = arr4; // int(&)[4]

5. Deduction with Functions

For functions, auto deduces to a function pointer.

example.cpp
1
2
int f5(int a) {return a;}
auto a5 = f5; // int(*)int

6. Deduction with auto&&

auto&& deduces a reference type.

  1. If the initializer is an lvalue, auto&& deduces an lvalue reference.
  2. If the initializer is an rvalue, auto&& deduces an rvalue reference.
example.cpp
1
2
3
4
int a6 = 3;
auto&& b6 = a6; // int&
auto&& c6 = 3; // int&&
auto&& d6 = std::move(a6); // int&&

7. Deduction with Lambda

auto can be used to deduce the return type of a lambda.

example.cpp
1
2
3
4
5
6
7
int a7 = 3;
auto lm1 = [](int x) {return x;};
auto lm2 = [](auto x) {return x;};
auto lm3 = [](int x) -> double {return x + 0.5;};
auto lm4 = [&]() -> decltype(auto) {
return a7; // Returns by reference
};

8. Deduction with decltype(auto)

decltype(auto) is used when you want the deduced type to match the initializer’s type exactly, including references.

example.cpp
1
2
3
int a8 = 42;
int& ref8 = a8;
decltype(auto) b8 = ref8; // int&

9. Deduction with auto*

auto* is deduced as a pointer type.

example.cpp
1
2
3
4
5
6
7
8
int a9 = 3;
auto* p1 = &a9; // int*, error case: auto p1 = a9, since a9 is not a pointer or an address
int arr[] = {1, 2, 3};
auto* p2 = arr; // int*
const int b9 = 3;
auto* p33 = &b9; // const int*
int* p4 = &a9;
auto* p5 = &p4; // int**
Author

Joe Chu

Posted on

2025-01-17

Updated on

2025-01-18

Licensed under

Comments