文章

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

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

C风格

传入指针

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

经典实现如下

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,代码比较不简洁。而且输入输出不分离,也不大优雅。

返回结构体

经典实现如下

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 风格

#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 您的编译器未必支持这么新的语法

#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++特性,绑定结构体,精妙而美丽。

c11/c17混用

当然我们也没必要全部使用c11的特性,或者全用c17的特性。

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

#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技术没有显示地给出返回值的意义,仅有类型。也就是说你得在注释里给出。

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

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

License:  CC BY 4.0