std::optional 的最佳替代方案是从方法返回可选值?(使用 C++98/C++11/C++14)



显然,如果使用 C++17 或 boost,std::optional 是从函数返回可选值的最佳选择(另请参阅 GOTW #90)

std::optional<double> possiblyFailingCalculation()

但是,如果一个人坚持使用旧版本(并且无法使用 boost),那么什么是最好的选择?

我看到几个选项:

  1. STL 智能指针(仅限 C++11)

    std::unique_ptr<double> possiblyFailingCalculation();
    
    • (+) 与可选用法几乎相同
    • (−) 混淆了指向非多态类型或内置类型的智能指针
  2. 将其与布尔值配对

    std::pair<double,bool> possiblyFailingCalculation();
    
  3. 旧式

    bool possiblyFailingCalculation(double& output);
    
    • (−) 与新的 C++11 auto value = calculation()样式不兼容
  4. DIY 模板:具有相同功能的基本模板很容易编码,但是实现一个强大的std::optional<T>类似模板有什么陷阱吗?

  5. 引发异常

    • (−) 有时"无法计算"是一个有效的返回值。

std::optional ,就像它的boost::optional父级一样,是一个非常基本的类模板。它是一个bool,一些存储和一堆方便的成员函数,其中大部分是一行代码和一个断言。

DIY选项绝对是首选。(1) 涉及分配和 (2)、(3) 涉及必须构造一个 T,即使你想要一个空值 - 这对double来说根本不重要,但对于更昂贵的类型来说确实很重要。对于 (5),例外不能替代optional

您可以随时将您的实现与 Boost 的进行比较。毕竟,这是一个仅包含标头的小型库。

我也会考虑一个哨兵值。

double的情况下,NaN值(std::numeric_limits<double>::quiet_NaN())是一个可能的候选值(只有在std::numeric_limits<double>::has_quiet_NaN == true时才有意义)。

关于这种方法有各种意见(例如,如果更喜欢使用 -ffast-math,请查看 NaN 或 false 作为双精度返回值和双精度的良好哨兵值)。

在特定域中,可能还有其他有意义的哨兵值。

无论如何(不仅对于double),我会采用/实现类似 markable (https://github.com/akrzemi1/markable) 的东西来避免魔术值并指示该值可能不存在,并且用户应该检查它的潜在缺失。

有关此方法的其他动机和概述:有效的可选值。

而不是std::optional,请使用此链接中的tl::optional:https://github.com/TartanLlama/optional

它具有与std对应的相同的公共接口,只是它也在 C++98 中编译。

我在生产代码 (C++11) 中使用它并且效果很好!

最新更新