auto lets the compiler deduce a type; const promises a value won't change; constexpr asks for it to be computed at compile time.
auto type deduction
#include <iostream>
#include <map>
#include <string>
#include <vector>
int main() {
auto n = 42; // int
auto pi = 3.14; // double
auto s = std::string("hi");
std::map<std::string, std::vector<int>> index{{"a", {1, 2}}};
for (const auto& [key, list] : index) // instead of spelling out the pair type
std::cout << key << ": " << list.size() << '\n';
std::cout << n << ' ' << pi << ' ' << s << '\n';
}a: 2
42 3.14 hi| You write | Deduced as | Why |
|---|---|---|
auto x = ci; (where const int ci) | int | Top-level const and references are dropped — you get a copy |
auto& r = ci; | const int& | A reference keeps const |
const auto& r = expr; | const T& | Read-only view, no copy — the default in range-for |
auto* p = &x; | int* | Documents that it's a pointer |
auto&& r = expr; | T& or T&& | Forwarding reference — binds to anything |
auto v = {1, 2}; | std::initializer_list<int> | Surprise! Braces with = deduce an initializer list |
const
#include <iostream>
int main() {
const int maxUsers = 100; // must be initialised; can't be changed later
int value = 5;
const int* p1 = &value; // pointer to const int: *p1 is read-only
int* const p2 = &value; // const pointer: p2 can't be re-seated
*p2 = 6; // OK — the int itself isn't const
p1 = &maxUsers; // OK — p1 itself isn't const
std::cout << *p1 << ' ' << value << '\n';
}100 6int main() {
const int limit = 10;
limit = 20; // error: cannot assign to a const variable
return limit;
}constexpr — compile-time values & functions
#include <array>
#include <iostream>
constexpr long long factorial(int n) { // may run at compile time
return n <= 1 ? 1 : n * factorial(n - 1);
}
int main() {
constexpr auto f10 = factorial(10); // computed by the compiler
static_assert(factorial(5) == 120); // checked at compile time
std::array<int, factorial(4)> arr{}; // usable as an array size
int n = 6;
std::cout << f10 << ' ' << arr.size() << ' ' << factorial(n) << '\n'; // also callable at run time
}3628800 24 720| Keyword | Meaning |
|---|---|
const | Can't be modified after initialisation. Value may be known only at run time. |
constexpr variable | Must be a compile-time constant (implies const). |
constexpr function | Can be evaluated at compile time if its arguments are constants; otherwise runs normally. |
consteval function (C++20) | Must be evaluated at compile time (an “immediate function”). |
constinit (C++20) | A static variable must be initialised at compile time, but can change later. |
#include <iostream>
consteval int square(int x) { return x * x; }
int main() {
constexpr int s = square(9); // fine: argument is a constant
std::cout << s << '\n';
// int n = 3; square(n); // error: n is not a constant expression
}81const everywhere it applies
What's the difference between const and constexpr?
Does auto make C++ dynamically typed?