如何在 C++ 中使用 std::optional ?

Posted

技术标签:

【中文标题】如何在 C++ 中使用 std::optional ?【英文标题】:How do I use std::optional in C++? 【发布时间】:2017-10-28 06:38:39 【问题描述】:

我正在尝试使用 std::optional 但我的代码引发错误。 我指定了#include <experimental/optional>,编译器选项为-std=c++1z-lc++experimental

std::experimental::optional怎么用?

以下是代码:

#include <experimental/optional>
#include <iostream>

std::experimental::optional<int> my_div(int x, int y) 
    if (y != 0) 
        int b = x / y;
        return b;
    
    else 
        return ;
    


int main() 
    auto res = my_div(6, 2);
    if (res) 
        int p = res.value();
        std::cout << p << std::endl;
    


错误信息:

optional.cpp:17:21: error: call to unavailable member function 'value': 
        int p = res.value();
                ~~~~^~~~~
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/experimental/optional:525:17: note: candidate function has been explicitly made unavailable
    value_type& value()
                ^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/experimental/optional:517:33: note: candidate function has been explicitly made unavailable
    constexpr value_type const& value() const
                                ^
1 error generated.

操作系统:macOS 10.12.5

编译器版本:

Apple LLVM version 8.1.0 (clang-802.0.42)
Target: x86_64-apple-darwin16.6.0
Thread model: posix
InstalledDir: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin

【问题讨论】:

通过 gcc 6.3.1 编译没有问题。您的编译器很可能对 C++1z 的支持水平不足。 对不起,我作为骗子的结束还为时过早。我发现(至少在我的 MAC 书上,也运行相同的编译器)有一个文件 /Library/Developer/CommandLineTools/usr/include/c++/v1/experimental/optional,所以这应该可以工作......但是,不幸的是,你没有向我们显示错误消息,所以我们可能无论如何都必须关闭它。 @Walter 我添加了错误消息。 【参考方案1】:

好的,在您发布错误后,我可以调查一下(但您也可以完全一样)。

简短

这是 Apple 在 OSX 上提供的 optional 的问题/错误,但有一个简单的解决方法。

发生了什么

文件/Library/Developer/CommandLineTools/usr/include/c++/v1/exper‌​imental/optional 将有问题的函数optional::value 声明为

template <class _Tp>
class optional
    : private __optional_storage<_Tp>

  /* ... */

  _LIBCPP_INLINE_VISIBILITY _LIBCPP_AVAILABILITY_BAD_OPTIONAL_ACCESS
  constexpr value_type const& value() const
  
    if (!this->__engaged_)
        throw bad_optional_access();
    return this->__val_;
  

  _LIBCPP_INLINE_VISIBILITY _LIBCPP_AVAILABILITY_BAD_OPTIONAL_ACCESS
  value_type& value()
  
    if (!this->__engaged_)
        throw bad_optional_access();
    return this->__val_;
  
  /* ... */
;

仅运行预处理器(编译器选项-E)显示宏扩展为

#define _LIBCPP_INLINE_VISIBILITY \
  __attribute__ ((__visibility__("hidden"), __always_inline__))
#define _LIBCPP_AVAILABILITY_BAD_OPTIONAL_ACCESS \
  __attribute__((unavailable))

特别是,_LIBCPP_AVAILABILITY_BAD_OPTIONAL_ACCESS 宏在文件/Library/Developer/CommandLineTools/usr/include/c++/v1/__config 中是#defined

// Define availability macros.
#if defined(_LIBCPP_USE_AVAILABILITY_APPLE)
// ...
#define _LIBCPP_AVAILABILITY_BAD_OPTIONAL_ACCESS __attribute__((unavailable))
// ...
#else
// ...
#define _LIBCPP_AVAILABILITY_BAD_OPTIONAL_ACCESS
// ...
#endif

因此,这是对 LLVM 的 libc++ API 的 Apple 特定更改。正如宏的名字所暗示的那样,原因是苹果不做

class bad_optional_access
: public std::logic_error

public:
  bad_optional_access() : std::logic_error("Bad optional Access") 
  virtual ~bad_optional_access() noexcept;
;

可用,因此无法实现依赖它的功能 (optional::value)。为什么不提供bad_optional_access(从而违反标准)尚不清楚,但这可能与必须更改库(dylib)以包含bad_optional_access::~bad_optional_access()这一事实有关。

如何解决

只需改用optional::operator*

int p = *res;

唯一真正的区别是没有进行访问检查。如果你需要,自己做吧

template<typename T>
T& get_value(std::experimental::optional<T> &opt)

  if(!opt.has_value())
    throw std::logic_error("bad optional access");
  return *opt;


template<typename T>
T const& get_value(std::experimental::optional<T>const &opt)

  if(!opt.has_value())
    throw std::logic_error("bad optional access");
  return *opt;

【讨论】:

“为什么不提供 bad_optional_access(从而违反标准)尚不清楚,但这可能与库 (dylib) 必须更改为包含 bad_optional_access::~bad_optional_access() 的事实有关。 "这是正确的。未来的操作系统版本将提供必要的符号,然后部署到这些版本或更高版本的应用程序将能够使用它。 @GregParker 你在这件事上与任何权威人士交谈吗?为什么要以这种方式设计故意破坏标准?

以上是关于如何在 C++ 中使用 std::optional ?的主要内容,如果未能解决你的问题,请参考以下文章

C++ 标准是不是允许在没有开销的情况下实现 std::optional<double>

如何在 Xcode 中获得 std::optional 支持?

Option类型:C++(std::optional)Rust(Option)Go(gob.OptionalValue)

如何在 if 语句中最好地测试和解包 std::optional

如何使用 std::optional<T>::emplace 的第二个重载

在 C++11 上下文中使用 std::optional