To be pedantically correct, you need to use one of these instead:
// `Foo` might have an overloaded `operator&`
foo.has_value() ? std::addressof(foo.value()) : nullptr
// You can shorten it to
foo ? std::addressof(*foo) : nullptr
// Or you can use `operator->()`
foo ? foo.operator->() : nullptr
// Which in C++20 can be accessed with a more readable utility function
foo ? std::to_address(foo) : nullptr
As for the "why", let's look at the proposal to add std::optional
to the standard library, "A proposal to add a utility class to represent optional objects (Revision 5)".
It's based on Boost.Optional, which does provide foo.get_ptr()
with the exact semantics that you want.
In fact, the original proposal has get_pointer(foo)
, but it was removed in the second revision. The change is described as "Removed duplicate interface for accessing the value stored by the optional.", as it was removed along with std::get(std::optional<T>&)
.
You can simply use boost::optional
instead, but it is not too hard to reimplement it yourself:
// If you want it as a member
namespace my {
template<typename T>
struct optional : std::optional<T> {
using std::optional<T>::optional;
T* get_ptr() noexcept { return has_value() ? std::addressof(value()) : nullptr; }
const T* get_ptr() const noexcept { return has_value() ? std::addressof(value()) : nullptr; }
};
}
// Or as a free function
template<typename T>
T* get_ptr(std::optional<T>& opt) noexcept {
return opt.has_value() ? std::addressof(opt.value()) : nullptr;
}
template<typename T>
const T* get_ptr(const std::optional<T>& opt) noexcept {
return opt.has_value() ? std::addressof(opt.value()) : nullptr;
}
Or using the C++23 monadic operations on optionals, this can be foo.and_then([](auto& x) { return std::addressof(x); })
.
&foo.value() ? foo.has_value() : nullptr
is not just "clunky" it is wrong. Iffoo
does not contain a value thenvalue()
throws an exception. – Godivahas_value
andvalue
in the code? – Godivabar(as_ptr(foo));
. – Stegosauras_ptr()
, you would need to check its result fornullptr
at the place where this result was used. I don't see any benefit over checking whether an optional has some value. – LightmanT const* as_ptr(std::optional<T> const&)
. – Regnantbar()
already does that. If I could re-writebar()
and all other functions like it to usestd::optional
instead of a pointer, then I wouldn't need to do this. – Trehalosebar
takes its parameter by pointer. You can't blamestd::optional
for that :P – Godivastd::construct_at
. A few years later, it got into the standard (not because of my question ;). But note that anyone can prepare a proposal for extending C++, including the addition of your desired function. – Lightmanoperator->
being undefined when the optional contains no value. If it could return anullptr
without incurring additional cost it would be the method you are looking for. – Godivanullptr
in case there is no value, it would be a replacement forfoo.has_value() ? &foo.value() : nullptr
– Godivaoperator->
explicitly to get a pointer. But, as 463 points out, the result is undefined if theoptional
doesn't contain a value, which is a bit of a shame. – Kev&foo.value()
or&*foo
, but none of these options would safely return nullptr when the optional is empty. – Trehalose