输入关键词开始搜索

C++ 类型推导 — auto 与 decltype

auto — 自动推导

auto i = 42;              // int
auto d = 3.14;            // double
auto s = "hello"s;        // std::string
auto v = vector{1,2,3};   // vector<int>

// ⚠️ auto 会丢掉引用和顶层 const
const int &cr = i;
auto x = cr;       // int(丢掉了 const 和 &)
auto &y = cr;      // const int &(保留引用,const 也随之保留)

// 保持 const
const auto z = cr; // const int

// C++14: auto 函数返回
auto sum(int a, int b) { return a + b; }

// C++20: auto 函数参数(简写模板)
// void foo(auto x) { }  等价于 template<typename T> void foo(T x) { }

auto 推导规则 = 模板推导规则

template <typename T>
void foo(T param);   // 传值 → 丢掉 const、引用、volatile

template <typename T>
void bar(T &param);  // 传引用 → 保留 const,T 推导为 const 类型

decltype — 获取声明类型

int x = 42;
decltype(x) y = 10;           // int

const int &cr = x;
decltype(cr) z = x;           // const int &(原封不动保留)

// decltype(表达式) — 表达式的值类别影响结果
decltype(x)    a = x;         // int(x 是变量名)
decltype((x))  b = x;         // int &((x) 是左值表达式!)

// 函数返回值
int foo();
decltype(foo()) result = foo(); // int

// 推导成员类型
vector<int> v;
decltype(v)::value_type val;    // int
decltype(v.begin()) it;         // vector<int>::iterator

decltype(auto) — C++14 的精确转发

// 场景:想完美转发函数的返回值类型
int &getRef();
int getVal();

// ❌ auto 丢掉引用
auto r1 = getRef();          // int

// ❌ decltype 需要重复表达式
decltype(getRef()) r2 = getRef();  // int &,但写了两遍

// ✅ decltype(auto) — 精确推导,不丢引用
decltype(auto) r3 = getRef();  // int &
decltype(auto) r4 = getVal();  // int

实用:完美转发函数返回值

template <typename F, typename... Args>
decltype(auto) invoke(F &&f, Args &&...args) {
    return forward<F>(f)(forward<Args>(args)...);
}

尾置返回类型

// 需要 decltype 参数 → 参数在返回类型后面
template <typename T, typename U>
auto multiply(T &&a, U &&b) -> decltype(a * b) {
    return a * b;
}

// C++14 简化
template <typename T, typename U>
decltype(auto) multiply(T &&a, U &&b) {
    return a * b;
}

// 实际场景:lambda 中
auto cmp = [](const auto &a, const auto &b) -> decltype(a < b) {
    return a < b;
};

实际应用

// 1. 范围 for
for (const auto &item : container) { }    // 避免拷贝
for (auto &&item : container) { }         // 万能引用

// 2. 结构化绑定(C++17)
map<string, int> m;
for (auto &&[key, value] : m) { }  // key=const string&, value=int&

auto [it, inserted] = m.insert({"x", 1});
// it = map::iterator, inserted = bool

// 3. 简化迭代器
auto it = v.begin();  // 替代 vector<int>::iterator

// 4. 通用 Lambda(C++14)
auto genericLambda = [](const auto &x, const auto &y) {
    return x + y;
};

速查表

写法行为保留引用保留 const
auto值语义推导
auto &左值引用
const auto &const 左值引用
auto &&万能引用取决于初始化值取决于初始化值
decltype(expr)精确推导表达式类型
decltype(var)精确推导变量声明类型
decltype((var))总是左值引用
decltype(auto)同 decltype,但免写表达式

不要过度使用

// ❌ — 类型信息丢失,可读性下降
auto result = someFunction();
// result 是什么?得跳转到 someFunction 才知道

// ✅ — 类型明确或无关紧要时用 auto
auto it = map.find(key);
for (const auto &x : vec) ...