| Document number |
P3259R0 |
| Date |
2024-05-09 |
| Reply-to |
Jarrad J. Waterloo <descender76 at gmail dot com>
|
| Audience |
Evolution Working Group (EWG) |
const by default
Table of contents
Abstract
Pure reference types with shallow const semantics would benefit from allowing adding a const modifier to a class definition in order to make them const by default and hence more consistent with the behavior of lvalue references.
Motivational Examples
function_ref
given
template<class... S> class function_ref;
template<class R, class... ArgTypes>
class function_ref<R(ArgTypes...) cv noexcept(noex)> const
{
};
usage
void action(){}
void some_other_action()
{
function_ref<void ()> fr1{ action };
mutable function_ref<void ()> fr2{ action };
fr1 = function_ref<void ()>{ action };
fr2 = function_ref<void ()>{ action };
std::vector<function_ref<void ()>> v1{ fr1, fr2 };
std::vector<mutable function_ref<void ()>> v2{ fr1, fr2 };
}
optional
given
template <class T>
class optional<T&> const
{
};
usage
int i = 42;
optional<int&> oi1{ i };
optional<const int&> oi2{ i };
mutable optional<int&> oi3{ i };
mutable optional<const int&> oi4{ i };
oi1 = i;
oi2 = i;
oi3 = i;
oi4 = i;
std::vector<optional<const int&>> v1{ oi1, oi2, oi3, oi4 };
std::vector<mutable optional<const int&>> v2{ oi1, oi2, oi3, oi4 };
Motivation
Lvalue references are immutable. "A reference is similar to a const pointer such as int* const p (as opposed to a pointer to const such as const int* p)" References and constant pointers are easier to reason about dangling. Since references are not reseatable and constant pointers are not by default reseatable, they are just aliases to the referent that they point to. This means at compile time, once they point to a global, local or temporary, they always point to said global, local or temporary. Further since the constness is baked in, a programmer is less likely to forget to add it.
Making pure reference types with shallow const semantics such as function_ref and optional<&> const by default would make them more consistent with lvalue references. This will make them easier to use safely as it is easier to reason about the lifetimes of the referents that they point to.
More Potential Examples
class a const{};
class b mutable{};
class c const(true){};
class d const(false){};
class e mutable(true){};
class f mutable(false){};
While at a minimum, only adding const to a class definition is needed, the other examples would be beneficial for completeness and to ease their usage in library definitions.
Should've, Could've, Would've
While not a part of this proposal, there are places in the standard library where types are implicitly const by default. For instance, adding the const by default class modifier to source_location, initializer_list, numeric_limits, integer_sequence, ration and all of the type traits would not have negative consequences as all of its member access is currently const only. It should also be noted that stacktrace_entry, span, mdspan, locale and all of the exceptions would also have been ideal candidates if it was not for their assignment operator. This is especially true of exeptions since they are usually thrown by value, catched by reference and rarely if ever reassigned mutably. The span class would also have been ideal since it is a lightweight pure reference type like function_ref and optional<&>. The basic_string_view is also in a similar situation of span, if it wasn't for its assignment operator, remove_prefix, remove_suffix and swap member functions. The last three member functions just as easily could have created a new basic_string_view since it is a cheap stack type like span.
References
Jarrad J. Waterloo <descender76 at gmail dot com>
const by default
Table of contents
Abstract
Pure reference types with shallow
constsemantics would benefit from allowing adding aconstmodifier to a class definition in order to make themconstby default and hence more consistent with the behavior of lvalue references.Motivational Examples
function_ref
given
usage
optional
given
usage
Motivation
Lvalue references are immutable. "A reference is similar to a const pointer such as int* const p (as opposed to a pointer to const such as const int* p)" [1] References and constant pointers are easier to reason about dangling. Since references are not reseatable and constant pointers are not by default reseatable, they are just aliases to the referent that they point to. This means at compile time, once they point to a global, local or temporary, they always point to said global, local or temporary. Further since the constness is baked in, a programmer is less likely to forget to add it.
Making pure reference types with shallow
constsemantics such asfunction_ref[2] andoptional<&>[3]const by defaultwould make them more consistent with lvalue references. This will make them easier to use safely as it is easier to reason about the lifetimes of the referents that they point to.More Potential Examples
While at a minimum, only adding
constto a class definition is needed, the other examples would be beneficial for completeness and to ease their usage in library definitions.Should've, Could've, Would've
While not a part of this proposal, there are places in the standard library where types are implicitly const by default. For instance, adding the const by default class modifier to
source_location,initializer_list,numeric_limits,integer_sequence,rationand all of the type traits would not have negative consequences as all of its member access is currentlyconstonly. It should also be noted thatstacktrace_entry,span,mdspan,localeand all of the exceptions would also have been ideal candidates if it was not for their assignment operator. This is especially true of exeptions since they are usually thrown by value, catched by reference and rarely if ever reassigned mutably. Thespanclass would also have been ideal since it is a lightweight pure reference type likefunction_refandoptional<&>. Thebasic_string_viewis also in a similar situation ofspan, if it wasn't for its assignment operator,remove_prefix,remove_suffixandswapmember functions. The last three member functions just as easily could have created a newbasic_string_viewsince it is a cheap stack type likespan.References
https://isocpp.org/wiki/faq/references#reseating-refs ↩︎
https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2023/p0792r14.html ↩︎
https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2024/p2988r4.pdf ↩︎