C++ 中的多返回值的实现

 

本文将循序渐进的从最古老的C风格开始,一直讲到C++17中多返回值的实现方法

C风格

传入指针

以指针形式传入待返回的值得地址,作为实参,并在类内对其赋值。

经典实现如下

1
2
3
4
5
6
void func(int a, int b, int *c, int *d)
{
// ... do sth with a,b

// 对*c,*d赋值
}

可以看出我们需要以func(a, b, &c, &d)这样的方式调用func,不仅不方便不直观,而且需要提前定义c, d,代码比较不简洁。而且输入输出不分离,也不大优雅。

返回结构体

经典实现如下

1
2
3
4
5
6
7
8
9
typedef struct{
int c;
int d;
} return_v;
retuen_v void func()
{
// do sth
return return_v{c, d};
}

麻烦就不说了,还污染了命名空间。而且再调用时,还要准备一个变量接受返回值,再从这个仅用一次的变量中取出需要的变量,太麻烦了。

modern c++ 风格

现代c++的多返回值得实现基本上用tuple实现,优雅而简洁。当然和python、go这种语言级的语法糖来说显得还是稍微麻烦一点的。不过有的人相较于语法糖形式的,说不定更喜欢这种学院派的泛型风格也说不定2333。

为什么不用pair

  1. pair可以完全被tuple取代。
  2. tuple泛用性更好。
  3. tuple在之后的c++标准中,有着更为重要的地位。也就是说会有越来越多的语法支持。

c++11 风格

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include <tuple>

std::tuple<int, int> divide(int dividend, int divisor) {
return std::make_tuple(dividend / divisor, dividend % divisor);
}

#include <iostream>

int main() {
using namespace std;

int quotient, remainder;

tie(quotient, remainder) = divide(14, 3);

cout << quotient << ',' << remainder << endl;
}

tie来绑定返回值从tuple。虽然比较方便,但是make_tuple这种形式还是稍显扭曲。

自从粗读了c++ stl的代码后,我越发觉得stl的作者太厉害了。就像是上文的这种多返回值语法,实现是非常精妙的。在不添加新的语法糖的情况下,在已有的语法框架下,实现了这么复杂的功能。这非常符合我少即是多的想法,而且统一性好多了2333。

c++17风格

warning 您的编译器未必支持这么新的语法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include <tuple>

std::tuple<int, int> divide(int dividend, int divisor) {
return {dividend / divisor, dividend % divisor};
}

#include <iostream>

int main() {
using namespace std;

auto [quotient, remainder] = divide(14, 3);

cout << quotient << ',' << remainder << endl;
}

用了新的c++特性,绑定结构体,精妙而美丽。

c++11/c++17混用

当然我们也没必要全部使用c++11的特性,或者全用c++17的特性。

他们不互相矛盾,可以这样混用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include <tuple>

std::tuple<int, int> divide(int dividend, int divisor) {
return {dividend / divisor, dividend % divisor};
}

#include <iostream>

int main() {
using namespace std;

tie(quotient, remainder) = divide(14, 3);

cout << quotient << ',' << remainder << endl;
}

缺点

tuple技术没有显示地给出返回值的意义,仅有类型。也就是说你得在注释里给出。

1
std::tuple<int, int> divide(int dividend, int divisor);  // return {quotient, remainder}

warning 如果你的项目中这一点非常重要还是使用结构体法吧。不过话说真的有人有这个需求吗。。。