std::optional 到 return 方法的可选值的最佳替代方案? (使用 C++98/C++11/C++14)
Best alternative to std::optional to return an optional value from a method? (using C++98/C++11/C++14)
显然,如果使用 C++17 或 boost,std::optional
是 return 函数可选值的最佳选择(另请参阅 GOTW #90)
std::optional<double> possiblyFailingCalculation()
但是如果一个人坚持使用旧版本(并且不能使用 boost),什么是最好的选择以及为什么是最好的选择?
我看到几个选项:
STL 智能指针(仅限 C++11)
std::unique_ptr<double> possiblyFailingCalculation();
- (+) 与 optional
几乎相同的用法
- (−) 混淆具有指向非多态类型或内置类型的智能指针
将其与布尔值配对
std::pair<double,bool> possiblyFailingCalculation();
旧样式
bool possiblyFailingCalculation(double& output);
- (−) 与新的 C++11
auto value = calculation()
风格不兼容
一个DIY模板:一个具有相同功能的基本模板很容易编写代码,但是实现一个健壮的模板有什么陷阱吗std::optional<T>
相似的模板 ?
抛出异常
- (−) 有时 "impossible to calculate" 是一个有效的 return 值。
std::optional
与其 boost::optional
父级一样,是一个非常基本的 class 模板。它是一个 bool
、一些存储和一堆方便的成员函数,其中大部分是一行代码和一个断言。
DIY 选项绝对是首选。 (1) 涉及分配,而 (2)、(3) 涉及必须构造一个 T
,即使您想要一个空值——这对 double
根本无关紧要,但对更昂贵的情况确实很重要类型。对于 (5),异常不能替代 optional
。
您始终可以将您的实施与 Boost 的实施进行比较。毕竟,这是一个仅包含头文件的小型库。
我也会考虑 sentinel value。
在 double
的情况下,NaN
值 (std::numeric_limits<double>::quiet_NaN()
) 是可能的候选值(仅当 std::numeric_limits<double>::has_quiet_NaN == true
时才有意义)。
对这种方法有多种看法(例如,看看 NaN or false as double precision return value and Good sentinel value for double if prefer to use -ffast-math)。
在特定域中,可能还有其他有意义的标记值。
在任何情况下(不仅仅是 double
)我会 adopt/implement 类似 markable
(https://github.com/akrzemi1/markable) 的东西来避免魔法值并表明该值可能不存在并且它可能不存在应该由用户检查。
有关此方法的额外动机和概述:Efficient optional values。
而不是 std::optional
,使用 link 中的 tl::optional
:
https://github.com/TartanLlama/optional
它与它的 std
对应物具有相同的 public 接口,只是它也在 C++98 中编译。
我在生产代码 (C++11) 中使用它并且效果很好!
显然,如果使用 C++17 或 boost,std::optional
是 return 函数可选值的最佳选择(另请参阅 GOTW #90)
std::optional<double> possiblyFailingCalculation()
但是如果一个人坚持使用旧版本(并且不能使用 boost),什么是最好的选择以及为什么是最好的选择?
我看到几个选项:
STL 智能指针(仅限 C++11)
std::unique_ptr<double> possiblyFailingCalculation();
- (+) 与 optional 几乎相同的用法
- (−) 混淆具有指向非多态类型或内置类型的智能指针
将其与布尔值配对
std::pair<double,bool> possiblyFailingCalculation();
旧样式
bool possiblyFailingCalculation(double& output);
- (−) 与新的 C++11
auto value = calculation()
风格不兼容
- (−) 与新的 C++11
一个DIY模板:一个具有相同功能的基本模板很容易编写代码,但是实现一个健壮的模板有什么陷阱吗
std::optional<T>
相似的模板 ?抛出异常
- (−) 有时 "impossible to calculate" 是一个有效的 return 值。
std::optional
与其 boost::optional
父级一样,是一个非常基本的 class 模板。它是一个 bool
、一些存储和一堆方便的成员函数,其中大部分是一行代码和一个断言。
DIY 选项绝对是首选。 (1) 涉及分配,而 (2)、(3) 涉及必须构造一个 T
,即使您想要一个空值——这对 double
根本无关紧要,但对更昂贵的情况确实很重要类型。对于 (5),异常不能替代 optional
。
您始终可以将您的实施与 Boost 的实施进行比较。毕竟,这是一个仅包含头文件的小型库。
我也会考虑 sentinel value。
在 double
的情况下,NaN
值 (std::numeric_limits<double>::quiet_NaN()
) 是可能的候选值(仅当 std::numeric_limits<double>::has_quiet_NaN == true
时才有意义)。
对这种方法有多种看法(例如,看看 NaN or false as double precision return value and Good sentinel value for double if prefer to use -ffast-math)。
在特定域中,可能还有其他有意义的标记值。
在任何情况下(不仅仅是 double
)我会 adopt/implement 类似 markable
(https://github.com/akrzemi1/markable) 的东西来避免魔法值并表明该值可能不存在并且它可能不存在应该由用户检查。
有关此方法的额外动机和概述:Efficient optional values。
而不是 std::optional
,使用 link 中的 tl::optional
:
https://github.com/TartanLlama/optional
它与它的 std
对应物具有相同的 public 接口,只是它也在 C++98 中编译。
我在生产代码 (C++11) 中使用它并且效果很好!