Document number |
P3326R0 |
Date |
2024-06-13 |
Reply-to |
Jarrad J. Waterloo <descender76 at gmail dot com>
|
Audience |
Library Evolution Working Group (LEWG) |
favor ease of use
Table of contents
Abstract
optional<&>
is a spectacularly safe by default
type. With only small additions to both optional<T>
and optional<T&>
, library writers will be able to make it even easier to use by allowing temporaries to be used in safe scenarios.
Motivational Example
p2988r5
given
optional<int&> dangler(optional<const int&> other,
optional<int&> left,
optional<int&> right)
{
if(random_bool())
{
return left;
}
else
{
return right;
}
}
usage
int i = 42;
optional<int&> oi1{i};
optional<int&> oi2 = dangler(oi1, oi1, oi1);
optional<int&> oi3 = dangler(42, oi1, oi1);
this proposal
given
optional<int&> dangler(optional<const int&, favors::ease> other,
optional<int&> left,
optional<int&> right)
{
if(random_bool())
{
return left;
}
else
{
return right;
}
}
usage
int i = 42;
optional<int&> oi1{i};
optional<int&> oi2 = dangler(oi1, oi1, oi1);
optional<int&> oi3 = dangler(42, oi1, oi1);
Requested Changes
- Add the
favors
enumeration
enum class favors
{
safety,
ease
};
- Add the default value of
favors::safety
to the original optional
template.
template <class T, favors favor = favors::safety>
class optional {
};
- Add the
favor
parameter to the std::optional<&>
specialization.
- Revise the
std::optional<&>
constructor by requiring favors::safety
.
- Add a constructor that takes a lvalue reference and requiring
favors::ease
.
template <class T, favors favor>
class optional<T&, favor> {
template <class U = T>
requires(!detail::is_optional<std::decay_t<U>>::value)
constexpr explicit(!std::is_convertible_v<U, T>) optional(U&& u) noexcept requires (favor == favors::safety)
: value_(std::addressof(u)) {
static_assert(
std::is_constructible_v<std::add_lvalue_reference_t<T>, U>
& favor == favors::safety,
"Must be able to bind U to T&");
static_assert(std::is_lvalue_reference<U>::value
& favor == favors::safety,
"U must be an lvalue");
}
constexpr optional(T& t) noexcept requires (favor == favors::ease)
: value_{std::addressof(t)} {}
}
- local variables
- return parameters just like
p2748r5
- member variables that are dependent upon constructor arguments
- input parameters that will be returned in whole or in part
favors::ease
- input parameters of functions that return void
- input parameters of functions that return values
- input parameters that will NOT be returned in whole or in part
Should've, Could've, Would've
The proposed functionality could be of benefit in other pure reference types. While that is out of scope of this proposal, it is worth mentioning the current impediments.
span
Span is not as safe by default
as std::optional<&>
since it allows binding to a temporary by default.
std::string_view sv1 = "42"s;
function_ref
It can be difficult to implement as parameter packs and default parameter values both live at the end of the template parameter list.
reference_wrapper
reference_wrapper
is the best existing pure reference type that could benefit from this enhancement. Its safety is comparable to that of std::optional<&>
. reference_wrapper
would need to be reimplemented and respecified before enhancing. Doing such would result in a safer replacement for &
itself.
Summary
This proposal identifies with Arthur O’Dwyer's article Value category is not lifetime
. While safety by default
is paramount, requiring that all libraries that use std::optional<&>
be needlessly difficult to use is detrimental to the clarity of our programs.
References
Jarrad J. Waterloo <descender76 at gmail dot com>
favor ease of use
Table of contents
favors::safety
vsfavors::ease
usageAbstract
optional<&>
[1] is a spectacularlysafe by default
type. With only small additions to bothoptional<T>
andoptional<T&>
[1:1], library writers will be able to make it even easier to use by allowing temporaries to be used in safe scenarios.Motivational Example
p2988r5 [1:2]
given
usage
this proposal
given
usage
Requested Changes
favors
enumerationfavors::safety
to the originaloptional
template.favor
parameter to thestd::optional<&>
[1:3] specialization.std::optional<&>
[1:4] constructor by requiringfavors::safety
.favors::ease
.favors::safety
vsfavors::ease
usagefavors::safety (i.e. the default)
p2748r5
[2]favors::ease
Should've, Could've, Would've
The proposed functionality could be of benefit in other pure reference types. While that is out of scope of this proposal, it is worth mentioning the current impediments.
span
Span is not as
safe by default
asstd::optional<&>
[1:5] since it allows binding to a temporary by default.function_ref
It can be difficult to implement as parameter packs and default parameter values both live at the end of the template parameter list.
reference_wrapper
reference_wrapper
is the best existing pure reference type that could benefit from this enhancement. Its safety is comparable to that ofstd::optional<&>
[1:6].reference_wrapper
would need to be reimplemented and respecified before enhancing. Doing such would result in a safer replacement for&
itself.Summary
This proposal identifies with Arthur O’Dwyer's article
Value category is not lifetime
[3]. Whilesafety by default
is paramount, requiring that all libraries that usestd::optional<&>
[1:7] be needlessly difficult to use is detrimental to the clarity of our programs.References
https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2024/p2988r5.pdf ↩︎ ↩︎ ↩︎ ↩︎ ↩︎ ↩︎ ↩︎ ↩︎
https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2024/p2748r5.html ↩︎
https://quuxplusone.github.io/blog/2019/03/11/value-category-is-not-lifetime/ ↩︎