C++的std::optional

解决函数多个返回值

为了解决C++函数返回多个值的问题,以前的做法通常是把返回指的指针作为入参传入,用函数的返回值作为运行状态的标识,比如下面这段,把指针output传入:

#include <iostream>

using namespace std;

int func(const string& str, string& out1, string& out2) {
    if (str.size() == 0)
        return 0;
    out1 = "hello";
    out2 = "world";
    return 1;
}

int main() {
    string out1, out2;
    int status = func("hi", out1, out2);
    if (status) {
        cout << out1 << endl;
        cout << out2 << endl;
    }
    return 0;
}

可读性会比较差。

C++11的做法

C++11新增了tuple,可以使用tuple返回多个值:

#include <iostream>
#include <tuple>

using namespace std;

tuple<bool, string, string> func(const string& in) {
    if (in.size() == 0)
        return make_tuple(false, "", "");
    return make_tuple(true, "hello", "world");
}

int main() {
    if (auto [status, out1, out2] = func("hi"); status) {
        cout << out1 << endl;
        cout << out2 << endl;
    }
    return 0;
}

需要刻意记住每个返回值的位置。

另一种方法是把数据定位一个pair,该pari包含函数返回标识,以及数据的Struct:

#include <iostream>

using namespace std;

struct Out {
    string out1 { "" };
    string out2 { "" };
};

pair<bool, Out> func(const string& in) {
    Out o;
    if (in.size() == 0)
        return { false, o };
    o.out1 = "hello";
    o.out2 = "world";
    return { true, o };
}

int main() {
    if (auto [status, o] = func("hi"); status) {
        cout << o.out1 << endl;
        cout << o.out2 << endl;
    }
    return 0;
}

C++17的做法

使用optional:

#include <iostream>
#include <optional>

using namespace std;

struct Out {
    string out1 { "" };
    string out2 { "" };
};

optional<Out> func(const string& in) {
    Out o;
    if (in.size() == 0)
        return nullopt;
    o.out1 = "hello";
    o.out2 = "world";
    return { o };
}

int main() {
    if (auto ret = func("hi"); ret.has_value()) {
        cout << ret->out1 << endl;
        cout << ret->out2 << endl;
    }
    return 0;
}

std::nullopt 是 C++ 17 中提供的没有值的 optional 的表达形式,等同于 { } 。

这样的好处:

  • 省去了运行状态的 bool 值的声明,让代码更简洁,更注重返回值本身的语意;
  • 不用担心额外的动态内存分配。
comments powered by Disqus