考虑以下程序:
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
可简化声明:我们将在 11.8 课 —— 多模板类型函数模板 中进一步讨论此类场景。// 让编译器推导 unsigned short + char 的结果类型 auto add(unsigned short x, char y) { return x + y; }
返回类型推导的缺点
必须先定义完整函数体,才能调用。前向声明不足!
auto foo(); // 仅前向声明 int main() { std::cout << foo(); // 错误:编译器无法推导返回类型 } auto foo() { return 5; }
报类似错误:
error C3779: 'foo': 返回 'auto' 的函数必须定义后才能使用
因此,返回
auto
的普通函数通常只能在定义所在文件内调用。接口不明确:函数声明不显示返回类型,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
在函数模板中的使用见多模板类型函数模板。