传统写c++函数的方式为,入参和出参都在一块,出参通常为引用,所以能看出来哪些是出参,而返回值通常为int,为0表示正常,为负数表示出错。然后每个函数调用之后,都需要使用if做一把判断。这当然也是一种行之有效的办法,而且简单好遵守,在各种大型项目都有使用。
现代的c++函数写法,可以不用通过引用接收多个返回值了,而由函数直接返回多个不同类型的值,就像python动态语言那样爽。尽管在性能和易于理解方面我持保留态度,不过,既然现代c++的设计标准里提供了,便学一学,多学无害。
以往如果是正好要返回两个值,那可以使用std::pair也就足够,如:
pair<string, int> get_name_and_height() {
return make_pair("zhang san", 180);
}
新的tuple便能支持多值返回,当然也包括两值,如:
tuple<int, float, string> run() {
return make_tuple(1, 3.14f, "haha");
}
int main()
{
int num;
float pi;
string name;
tie(num, pi, name) = run();
return 0;
}
这种写法跟PHP里的list()写法很像,还是有些繁琐,据说最新版本的c++编译器(>=c++17)已经支持类似Python的写法了:
auto [num, pi, name] = run();
其实就是如何去解绑tuple数据,最新的写法有点太pythonic了,简直不像C++。
实际工程实践中,会有返回值增加的时候,如果某个函数返回的值要多一个,就得把所有调用的位置都修改一遍也是很心累的,所以也可以按位置手动去取结果:
auto ret = run();
cout << std::get<0>(ret) << std::get<1>(ret) << std::get<2>(ret) << endl;
这个解决了兼容问题,但是却解决不了难以理解的问题,时间久了,鬼才知道位置1处是代表啥意思。
除了tuple,更推荐的是使用临时结构体来返回,兼容性好,也易读:
auto run2() {
struct Ret {
int n;
float pi;
string name;
};
return Ret{1, 3.14f, "haha"};
}
int main()
{
auto ret2 = run2();
cout << typeid(ret2).name() << " " << ret2.n << ret2.pi << ret2.name << endl;
}
有人可能又会说了,既然是临时结构体,我压根就不关心它叫什么,我只关心它有哪些字段,所以连定义这个结构体都是很麻烦的事,那么就可以简写成如下形式:
auto run2() {
return (struct{ int n; float pi; string name; }){1, 3.14f, "haha"};
}
int main()
{
auto ret2 = run2();
cout << typeid(ret2).name() << " " << ret2.n << ret2.pi << ret2.name << endl;
}
回到最初,如果没有返回值来确定状态,如何知道返回的结果是否可用呢?我也在琢磨这个问题,感觉现在的c++写法从设计上更推崇使用try...catch()来处理不正常状态,原来那种一堆对返回值的if判断的写法,也确实恶心,不过它又管用。