在C++primer
中所说的编译器会推断return_type
的情况,翻译原文如下:
“如果函数体只是一个return
语句,则返回类型从返回的表达式的类型推断而来。否则,返回类型为void
。”
那么,今天我们来验证一下这句话是否正确。
示例1:
#include <iostream>
int main () {
auto f = [](int a, int b) {
return a + b;
};
std::cout << typeid(f(1, 1)).name() << std::endl;
}
上面示例函数体只有单一return
语句且缺省return_type
,typeid(f(1, 1)).name()
用于检测返回类型。
输出:
i
代表其返回值为int
。
这个实验验证了“如果函数体只是一个return
语句,则返回类型从返回的表达式的类型推断而来。”这句话的正确性。但是后半句话“否则,返回类型为void
。”是否正确呢?
示例2:
#include <iostream>
int main () {
auto f = [](int a, int b) {
// 增加内容起始位置
std::cout << "try to do something" << std::endl;
a *= 10;
b *= 10;
// 增加内容终止位置
return a + b;
};
std::cout << typeid(f(1, 1)).name() << std::endl;
}
这段代码在示例1的基础上增加了三行代码,进行简单输出与简单计算。但是编译器仍然完成了类型推断。
输出:
i
仍然正确推断返回类型。
示例3:
#include <iostream>
int main () {
auto f = [](int a, int b) {
std::cout << "try to do something" << std::endl;
// 修改内容起始位置
if(a) {
a *= 10;
b *= 10;
return a + b;
} else {
return a - b;
}
// 修改内容终止位置
};
std::cout << typeid(f(1, 1)).name() << std::endl;
}
上面代码增加了if_else
分支语句,每条分支上都存在一个return
语句,但是return
的值都是int
类型。
输出:
i
仍然能正确推断出返回类型。
示例2和示例3说明:即使函数体不止一个return
语句,返回类型也可以从返回的表达式的类型推断而来。
那么在什么情况下,编译器无法完成类型推断的工作呢?
示例4:
#include <iostream>
int main () {
auto f = [](int a, int b) {
std::cout << "try to do something" << std::endl;
if(a) {
a *= 10;
b *= 10;
return a + b;
} else {
// 修改内容起始位置
return "string_type";
// 修改内容终止位置
}
};
std::cout << typeid(f(1, 1)).name() << std::endl;
}
上述代码在示例3的基础上修改了第二条分支语句的return a + b
为return "string_type"
,即两条分支语句拥有不同的返回类型,这个时候语法检查会提醒deduced return type "const char *" conflicts with previously deduced type "int"C/C++(2546)
,即“推断出的返回类型 ‘const char *’ 与之前推断出的类型 ‘int’ 冲突”。所以这种情况下,lambda是没有办法推断出返回类型的。
综上,C++primer
中的那段话并不完全正确。只要你所有return
语句都使用相同的类型,那么返回类型就可以由编译器自动推断。