auto and decltype — C++
auto — Type Deduction (C++11)
auto tells the compiler to deduce the type from the initializer. Reduces verbosity and keeps code in sync with type changes.
Variable examples:
auto x = 42; // int
auto pi = 3.14; // double
auto s = std::string{"hello"}; // std::string
auto it = vec.begin(); // std::vector<int>::iterator
Return type deduction (C++14):
auto add(int a, int b) { return a + b; } // return type: int
Structured bindings (C++17):
std::pair<int, std::string> p{1, "one"};
auto [num, name] = p; // num: int, name: std::string
decltype — Type Introspection
decltype(expr) yields the type of an expression without evaluating it.
int x = 0;
decltype(x) y = 5; // y is int
decltype(x + 0.0) z = 1.5; // z is double
std::vector<int> v;
decltype(v)::iterator it = v.begin(); // vector<int>::iterator
decltype(auto) (C++14) — deduces type including references and cv-qualifiers:
int x = 42;
int& ref = x;
decltype(auto) a = ref; // a is int& (reference preserved)
auto b = ref; // b is int (reference stripped)
Trailing Return Types
Used when the return type depends on parameter types:
template <typename A, typename B>
auto multiply(A a, B b) -> decltype(a * b) {
return a * b;
}
auto in Lambdas (C++14 Generic Lambdas)
auto greet = [](auto name) {
return std::string("Hello, ") + name;
};
greet("world"); // works with any string-like type
Common Pitfalls
auto strips references and cv-qualifiers:
const int& cref = x;
auto a = cref; // a is int (not const int&!)
auto& b = cref; // b is const int& (reference preserved)
const auto& c = cref; // c is const int&
[!WARNING] When using
autowith references or const-qualified types, always add&orconst auto&to preserve those qualifiers.
auto Type Deduction Flow
flowchart TD A[“auto x = expr”] –> B{“Is expr a reference?”} B –>|”Yes”| C[“Strip reference”] C –> D{“Has cv-qualifiers?”} B –>|”No”| D D –>|”Yes”| E[“Strip cv-qualifiers”] D –>|”No”| F[“Deduce base type”] E –> F F –> G[“x has deduced type”]
decltype vs auto Decision
flowchart TD A[“Need to capture a type”] –> B{“Preserve references and cv?”} B –>|”Yes”| C[“Use decltype(auto)”] B –>|”No”| D{“Have initializer expression?”} D –>|”Yes”| E[“Use auto”] D –>|”No”| F{“Have an expression to inspect?”} F –>|”Yes”| G[“Use decltype(expr)”] F –>|”No”| H[“Use explicit type”]
Summary Table
| Feature | Syntax | What it deduces | Notes |
|---|---|---|---|
auto variable | auto x = expr; | Type of expr (strips ref/cv) | C++11 |
auto return | auto fn() { ... } | Return expression type | C++14 |
| Structured binding | auto [a,b] = pair; | Member types | C++17 |
decltype(expr) | decltype(x+1) v; | Exact type of expression | No evaluation |
decltype(auto) | decltype(auto) x = expr; | Type preserving ref and cv | C++14 |
| Trailing return | auto f() -> decltype(...) | Expression-dependent return | C++11 |