web-dev-qa-db-ja.com

C ++でstd :: optionalを使用するにはどうすればよいですか?

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.

OS: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
12
KiYugadgeter

さて、あなたがあなたのエラーを投稿した後、私はそれを調べることができました(しかしあなたはまったく同じことをすることができたでしょう)。

短期間

これは、OSXでApple=によって提供される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_はファイル_#define_の_/Library/Developer/CommandLineTools/usr/include/c++/v1/__config_ dです。

_// 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
_

したがって、これはApple 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_が提供されない(それによって標準に違反する)理由は不明ですが、bad_optional_access::~bad_optional_access()を含むようにライブラリ(dylib)を変更する必要があるという事実に関係している可能性があります。

回避策

代わりに_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;
}
_
16
Walter