I am trying to use std::optional but my code raise error.
I have specified #include <experimental/optional>
and compiler options are -std=c++1z
, -lc++experimental
.
How to use std::experimental::optional
?
The following is code:
#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;
}
}
error message:
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
Compiler version:
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
The class template std::optional manages an optional contained value, i.e. a value that may or may not be present. A common use case for optional is the return value of a function that may fail.
std::optional Operations If you have existing optional object, then you can easily change the contained value by using several operations like emplace , reset , swap , assign. If you assign (or reset) with a nullopt then if the optional contains a value its destructor will be called.
optional is required to not use dynamic allocation. If an optional contains a value, the value is guaranteed to be allocated as part of the optional object footprint, i.e. no dynamic memory allocation ever takes place.
C++17 introduced std::optional<T> which lets you augment the values of a type T with a bonus value known as std::nullopt which semantically represents the absence of a value. A std::optional which holds the value std::nullopt is known as empty.
Okay, after you posted your error, I could look into that (but you could have done exactly the same).
IN SHORT
This is a problem/bug with optional
as provided by Apple on OSX, but there is an easy workaround.
WHAT'S GOING ON
The file /Library/Developer/CommandLineTools/usr/include/c++/v1/experimental/optional
declares the offending function optional::value
as
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_;
}
/* ... */
};
Running the preprocessor only (compiler option -E
) reveals that the macros expand to
#define _LIBCPP_INLINE_VISIBILITY \
__attribute__ ((__visibility__("hidden"), __always_inline__))
#define _LIBCPP_AVAILABILITY_BAD_OPTIONAL_ACCESS \
__attribute__((unavailable))
In particular, the macro _LIBCPP_AVAILABILITY_BAD_OPTIONAL_ACCESS
is #define
d in file /Library/Developer/CommandLineTools/usr/include/c++/v1/__config
as
// 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
Thus, this is a Apple specific change from LLVM's libc++ API. As the name of the macro implies, the reason is that Apple does not make
class bad_optional_access
: public std::logic_error
{
public:
bad_optional_access() : std::logic_error("Bad optional Access") {}
virtual ~bad_optional_access() noexcept;
};
available and hence cannot implement functionality (optional::value
) that depends on it. Why bad_optional_access
is not provided (thereby breaking the standard) is unclear, but it may have to do with the fact that a library (dylib) must be altered to contain bad_optional_access::~bad_optional_access()
.
HOW TO WORK AROUND
simply use optional::operator*
instead
int p = *res;
The only real difference is that no access check is done. If you need that, do it yourself
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;
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With