函数的类型推导

考虑以下程序:

int add(int x, int y)
{
    return x + y;
}

编译时,编译器会判断 x + y 的结果为 int,并确保返回值类型与函数声明的返回类型匹配(或可转换)。

返回类型推导:使用 auto

从 C++14 开始,auto 被扩展用于函数返回类型的推导。将 auto 置于函数返回类型位置即可:

auto add(int x, int y)
{
    return x + y;   // 返回 int,编译器推导出返回类型为 int
}

使用 auto 返回类型时,函数内所有 return 语句必须返回相同类型,否则报错:

auto someFcn(bool b)
{
    if (b)
        return 5;    // int
    else
        return 6.7;  // double
}                    // 错误:返回类型不一致

若确实需要不同返回类型,可:

  • 显式指定返回类型,让编译器做隐式转换;或
  • static_cast 把所有返回值显式转成同一类型。上例可把 5 改为 5.0,或用 static_cast<double>(5)

返回类型推导的优点

最大优势是消除返回类型不匹配的风险(避免意外转换)。

  • 当返回类型极易随实现变动(脆弱返回类型)时,显式写死返回类型意味着每次实现变动都要同步修改,而 auto 可自动适应。
  • 若返回类型冗长或不易书写,auto 可简化声明:
    // 让编译器推导 unsigned short + char 的结果类型
    auto add(unsigned short x, char y)
    {
        return x + y;
    }
    
    我们将在 11.8 课 —— 多模板类型函数模板 中进一步讨论此类场景。

返回类型推导的缺点

  1. 必须先定义完整函数体,才能调用。前向声明不足

    auto foo();           // 仅前向声明
    int main()
    {
        std::cout << foo(); // 错误:编译器无法推导返回类型
    }
    auto foo() { return 5; }
    

    报类似错误:

    error C3779: 'foo': 返回 'auto' 的函数必须定义后才能使用
    

    因此,返回 auto 的普通函数通常只能在定义所在文件内调用。

  2. 接口不明确:函数声明不显示返回类型,IDE 可提示,但无 IDE 时需查看实现才能知晓。接口类型的清晰性通常更重要。

综上,一般应避免返回类型推导

最佳实践

优先使用显式返回类型,除非返回类型不重要、难以书写或极易变动。

尾随返回类型语法

auto 也可用于尾随返回类型(trailing return type):

int add(int x, int y)
{
    return x + y;
}
// 等价写法
auto add(int x, int y) -> int
{
    return x + y;
}

此时 auto 不执行任何推导,仅构成语法的一部分。

使用场景:

  • 复杂返回类型:
    // 传统写法难读
    std::common_type_t<int, double> compare(int, double);
    // 尾随写法易读
    auto compare(int, double) -> std::common_type_t<int, double>;
    
  • 对齐函数名,提高连续声明可读性:
    auto add(int x, int y) -> int;
    auto divide(double x, double y) -> double;
    auto printSomething() -> void;
    auto generateSubstring(const std::string& s, int start, int len) -> std::string;
    

供进阶读者

若返回类型需依赖形参类型,传统写法无法使用形参名;尾随写法可用 decltype

#include <type_traits>
// 非法:编译器尚未见到 x, y
std::common_type_t<decltype(x), decltype(y)> add(int x, double y);
// 合法
auto add(int x, double y)
    -> std::common_type_t<decltype(x), decltype(y)>;

Lambda 表达式(20.6 课)也要求尾随语法。 目前建议:除必需场景,仍使用传统返回类型语法。

函数参数不支持类型推导

许多新手写出:

void addAndPrint(auto x, auto y)
{
    std::cout << x + y << '\n';
}

在 C++20 之前,上述代码无法编译(错误:形参不能使用 auto)。

C++20 起,该写法可通过编译,但这里的 auto 并非类型推导,而是触发了函数模板机制。

相关内容 auto 在函数模板中的使用见多模板类型函数模板。

关注公众号,回复"cpp-tutorial"

可领取价值199元的C++学习资料

公众号二维码

扫描上方二维码或搜索"cpp-tutorial"