[libcxx-commits] [libcxx] [libc++] Fix bug where optional<T&> couldn't be constructed from a monadic operation (PR #203462)
A. Jiang via libcxx-commits
libcxx-commits at lists.llvm.org
Thu Jun 11 23:17:30 PDT 2026
================
@@ -571,6 +571,14 @@ struct __optional_storage_base<_Tp, true> {
__convert_init_ref_val(std::forward<_UArg>(__uarg));
}
+# if _LIBCPP_STD_VER >= 23
+ template <class _Fp, class... _Args>
+ constexpr __optional_storage_base(__optional_construct_from_invoke_tag, _Fp&& __f, _Args&&... __args) {
+ _Tp& __r = std::invoke(std::forward<_Fp>(__f), std::forward<_Args>(__args)...);
----------------
frederick-vs-ja wrote:
Shouldn't this be direct-non-list-initialization? See [[optional.monadic]](https://eel.is/c++draft/optional.monadic), [[optional.ref.monadic]](https://eel.is/c++draft/optional.ref.monadic).
```suggestion
_Tp& __r(std::invoke(std::forward<_Fp>(__f), std::forward<_Args>(__args)...));
```
The difference is quite observable. [Godbolt link](https://godbolt.org/z/xcxKPsrsE). Perhaps we should add new test cases to ensure that copy-initialization isn't accidentally used.
```C++
struct X {
explicit operator int&() const;
};
struct Y {
template <class = void>
operator int&() const;
explicit operator int&() const = delete;
};
int& r1 = X{}; // error
int& r2(X{}); // OK
int& r3 = Y{}; // OK
int& r4(Y{}); // error
```
https://github.com/llvm/llvm-project/pull/203462
More information about the libcxx-commits
mailing list