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

KiY*_*ter 8 c++ c++17 stdoptional

我试图使用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;
    }
}
Run Code Online (Sandbox Code Playgroud)

错误信息:

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.
Run Code Online (Sandbox Code Playgroud)

操作系统: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
Run Code Online (Sandbox Code Playgroud)

Wal*_*ter 16

好的,在你发布错误之后,我可以调查一下(但你可以完全相同).

简而言之

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

这是怎么回事

该文件/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_;
  }
  /* ... */
};
Run Code Online (Sandbox Code Playgroud)

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

#define _LIBCPP_INLINE_VISIBILITY \
  __attribute__ ((__visibility__("hidden"), __always_inline__))
#define _LIBCPP_AVAILABILITY_BAD_OPTIONAL_ACCESS \
  __attribute__((unavailable))
Run Code Online (Sandbox Code Playgroud)

具体地,宏_LIBCPP_AVAILABILITY_BAD_OPTIONAL_ACCESS#defined在文件/Library/Developer/CommandLineTools/usr/include/c++/v1/__config作为

// 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
Run Code Online (Sandbox Code Playgroud)

因此,这是来自LLVM的libc ++ API的Apple特定更改.正如宏的名称所暗示的那样,原因在于Apple没有制造

class bad_optional_access
: public std::logic_error
{
public:
  bad_optional_access() : std::logic_error("Bad optional Access") {}
  virtual ~bad_optional_access() noexcept;
};
Run Code Online (Sandbox Code Playgroud)

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

如何工作

只需optional::operator*改用

int p = *res;
Run Code Online (Sandbox Code Playgroud)

唯一真正的区别是没有进行访问检查.如果您需要,请自己动手

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;
}
Run Code Online (Sandbox Code Playgroud)

  • @GregParker 您是否就此事发表过任何权威意见?为什么这样设计是故意刹车标准的? (3认同)
  • "为什么不提供bad_optional_access(从而违反标准)尚不清楚,但它可能与必须改变库(dylib)以包含bad_optional_access ::〜bad_optional_access()的事实有关." 那就对了.未来的操作系统版本将提供必要的符号,然后部署到这些版本或更新版本的应用程序将能够使用它. (2认同)