This page is a snapshot from the LWG issues list, see the Library Active Issues List for more information and the meaning of Open status.
constexpr
Section: 22.6.3.2 [variant.ctor] Status: Open Submitter: Richard Smith Opened: 2016-11-28 Last modified: 2024-06-24
Priority: 2
View other active issues in [variant.ctor].
View all other issues in [variant.ctor].
View all issues with Open status.
Discussion:
The library has lots of functions declared constexpr
, but it's not clear what that means. The constexpr
keyword implies that there needs to be some invocation of the function, for some set of template
arguments and function arguments, that is valid in a constant expression (otherwise the program would be ill-formed,
with no diagnostic required), along with a few side conditions. I suspect the library intends to require something a
lot stronger than that from implementations (something along the lines of "all calls that could reasonably be constant
subexpressions are in fact constant subexpressions, unless otherwise stated").
[variant.ctor]/1 contains this, which should also be fixed:
"This function shall be
constexpr
if and only if the value-initialization of the alternative typeT0
would satisfy the requirements for aconstexpr
function."
This is the wrong constraint: instead of constraining whether the function is constexpr
, we should constrain
whether a call to it is a constant subexpression.
Daniel:
This is has some considerable overlap with LWG 2289 but is phrased in a more general way.
[2016-12-16, Issues Telecon]
Priority 2; this is also the general case of 2829.
[2017-02-20, Alisdair comments and suggests concrete wording]
Below is is draft wording I was working on at Issaquah to try to address both issues.
[2017-11 Albuquerque Wednesday issue processing]
Status to Open; really needs a paper.
STL says "What about plus<T>
?" plus<int>
needs to be usable in a constexpr context, but plus<string>
can't be.
[2017-11 Albuquerque Saturday issues processing]
Geoffrey to write a paper resolving this.
[2018-06 Rapperswil Thursday issues processing]
Geoffrey has been unable to write this paper due to time constraints. He wrote up his progress here. Daniel has offered to help someone to write this paper; he's willing to be a co-author.
[2018-08-23 Batavia Issues processing]
Michael Wong to investigate.
Previous resolution from Daniel [SUPERSEDED]:This wording is relative to N4640.
Modify 16.4.6.7 [constexpr.functions] as indicated:
17.6.5.6
constexpr
functions and constructors [constexpr.functions]-1- This International Standard explicitly requires that certain standard library functions are
constexpr
(9.2.6 [dcl.constexpr]). If the specification for a templated entity requires that it shall be aconstexpr
templated entity, then that templated entity shall be usable in a constant expression.. An implementationshall notmay declareanyadditional standard library function signature asconstexpr
except for those where it is explicitly required. Within any header that provides any non-defining declarations ofconstexpr
functions or constructors an implementation shall provide corresponding definitions.
[2020-06-08 Nina Dinka Ranns comments and provides alternative wording]
The revised wording draft also resolves LWG 2289, LWG 2829, and LWG 3215.
Previous resolution [SUPERSEDED]:This wording is relative to N4861.
1. Modify 16.4.6.7 [constexpr.functions] as indicated:
-1- This document explicitly requires that certain standard library functions are
constexpr
(9.2.6 [dcl.constexpr]). An implementation shall not declare any standard library function signature asconstexpr
except for those where it is explicitly required. Within any header that provides any non-defining declarations of constexpr functions or constructors an implementation shall provide corresponding definitions.-?- Let
F
denote a standard library function template or member function of a class template. If the specification ofF
declares it to beconstexpr
, unless otherwise specified, thenF
can be used in a constant expression if and only if all the expressions that are evaluated as specified in the description ofF
's semantics can be used in a constant expression.2. - 10. […] // Remainder of Nina's update
[2020-10-02 Jens Maurer improves wording]
Specifically the wording for 16.4.6.7 [constexpr.functions] needs improvement and is updated below.
[2020-10-02 Tim Song comments]
The new wording doesn't cover the following example:
// global scope int x; int y; constexpr int j = (std::swap(x, y), 0); // error
swap
is a "standard library function template...declared constexpr
"
x
and y
are (lvalue) constant expressions
std::swap(x, y)
is plainly not a constant expression
[2020-10-04 Jens Maurer comments]
Yes, we're still lacking text for that (and maybe Nina's old text helps for that).
[2020-12-14; Jiang An comments]
The item "constexpr functions" is also used in 24.2.2 [container.requirements.general]/14 and 25.3.1 [iterator.requirements.general]/16, and such usage should also be modified by this issue here.
[St. Louis 2024-06-24;
Re-confirmed Tim's previous observation, new P/R needed.
Jens says there are two ways that swap
could work, and the library doesn't
actually say how it does what it does, so it's not possible for a reader to
know whether they can expect it to be usable in a constant expression.
]
Proposed resolution:
This wording is relative to N4861.
Modify 16.4.6.7 [constexpr.functions] as indicated:
-1- This document explicitly requires that certain standard library functions are
constexpr
(9.2.6 [dcl.constexpr]). An implementation shall not declare any standard library function signature asconstexpr
except for those where it is explicitly required. Within any header that provides any non-defining declarations of constexpr functions or constructors an implementation shall provide corresponding definitions.-?- Let
F
denote a standard library function template or member function of a class template declaredconstexpr
. Unless otherwise specified, a function call expression (7.6.1.3 [expr.call]) whose postfix-expression namesF
is a constant expression if all of the argument subexpressions are constant expressions.
Modify 22.3.2 [pairs.pair] as indicated:
-2- The defaulted
move and copyconstructors, respectively,ofpair
is a constexpr functioncan be used in a constant expression if and only if all required element-wise initializationsfor move and copy, respectively, would satisfy the requirements for a constexpr functioncan be used in a constant expression.
Modify 22.4.4.2 [tuple.cnstr] as indicated:
-3- The defaulted
move and copyconstructors, respectively,oftuple
is a constexpr functioncan be used in a constant expression if and only if all required element-wise initializationsfor move and copy, respectively, would satisfy the requirements for a constexpr functioncan be used in a constant expression. The defaultedmove and copyconstructors oftuple<>
are constexpr functionscan be used in a constant expression.
Modify 22.5.3.2 [optional.ctor] as indicated:
constexpr optional() noexcept; constexpr optional(nullopt_t) noexcept;[…]-1- […]
-2- Remarks: No contained value is initialized.
For every object typeT
these constructors are constexpr constructors (9.2.6 [dcl.constexpr]).template<class... Args> constexpr explicit optional(in_place_t, Args&&... args);-12- […]
-13- […]
-14- […]
-15- […]
-16- Remarks: IfT
's constructor selected for the initialization is a constexpr constructor, this constructor is a constexpr constructor.template<class U, class... Args> constexpr explicit optional(in_place_t, initializer_list<U> il, Args&&... args);-17- […]
-18- […]
-19- […]
-20- […]
-21- Remarks: IfT
's constructor selected for the initialization is a constexpr constructor, this constructor is a constexpr constructor.template<class U = T> constexpr explicit(see below) optional(U&& v);-22- […]
-23- […]
-24- […]
-25- […]
-26- Remarks:
IfThe expression insideT
's constructor selected for the initialization is a constexpr constructor, this constructor is a constexpr constructor.explicit
is equivalent to:!is_convertible_v<U, T>
Modify 22.5.3.7 [optional.observe] as indicated:
constexpr const T* operator->() const; constexpr T* operator->();-1- […]
-2- […]
-3- […]
-4- Remarks: These functions are constexpr functions.constexpr const T& operator*() const&; constexpr T& operator*() &;[…]-5- […]
-6- […]
-7- […]
-8- Remarks: These functions are constexpr functions.constexpr explicit operator bool() const noexcept;-11- Returns:
true
if and only if*this
contains a value.
-12- Remarks: This function is a constexpr function.constexpr bool has_value() const noexcept;-13- Returns:
true
if and only if*this
contains a value.
-14- Remarks: This function is a constexpr function.
Modify 22.5.6 [optional.relops] as indicated:
template<class T, class U> constexpr bool operator==(const optional<T>& x, const optional<U>& y);-1- […]
-2- […]
-3- Remarks: Specializations of this function template for which*x == *y
is a core constant expression are constexpr functions.template<class T, class U> constexpr bool operator!=(const optional<T>& x, const optional<U>& y);-4- […]
-5- […]
-6- Remarks: Specializations of this function template for which*x != *y
is a core constant expression are constexpr functions.template<class T, class U> constexpr bool operator<(const optional<T>& x, const optional<U>& y);-7- […]
-8- […]
-9- Remarks: Specializations of this function template for which*x < *y
is a core constant expression are constexpr functions.template<class T, class U> constexpr bool operator>(const optional<T>& x, const optional<U>& y);-10- […]
-11- […]
-12- Remarks: Specializations of this function template for which*x > *y
is a core constant expression are constexpr functions.template<class T, class U> constexpr bool operator<=(const optional<T>& x, const optional<U>& y);-13- […]
-14- […]
-15- Remarks: Specializations of this function template for which*x <= *y
is a core constant expression are constexpr functions.template<class T, class U> constexpr bool operator>=(const optional<T>& x, const optional<U>& y);-16- […]
-17- […]
-18- Remarks: Specializations of this function template for which*x >= *y
is a core constant expression are constexpr functions.template<class T, three_way_comparable_with<T> U> constexpr compare_three_way_result_t<T,U> operator<=>(const optional<T>& x, const optional<U>& y);-19- Returns: If
x && y
,*x <=> *y
; otherwisebool(x) <=> bool(y)
.
-20- Remarks: Specializations of this function template for which*x <=> *y
is a core constant expression are constexpr functions.
Modify 22.6.3.2 [variant.ctor] as indicated:
constexpr variant() noexcept(see below);[…]-1- […]
-2- […]
-3- […]
-4- […]
-5- […]
-6- Remarks:
This function isThe expression insideconstexpr
if and only if the value-initialization of the alternative typeT_{0}
would satisfy the requirements for a constexpr function.noexcept
is equivalent tois_nothrow_default_constructible_v<T_{0}>
. [Note: See also classmonostate
. — end note]template<class T> constexpr variant(T&& t) noexcept(see below);-14- […]
[…]
-19- Remarks: The expression inside
noexcept
is equivalent tois_nothrow_constructible_v<T_{j}, T>
.IfT_{j}
's selected constructor is a constexpr constructor, this constructor is a constexpr constructor.template<class T, class... Args> constexpr explicit variant(in_place_type_t<T>, Args&&... args);-20- […]
[…]
-24- Remarks: IfT
's selected constructor is a constexpr constructor, this constructor is a constexpr constructor.template<class T, class U, class... Args> constexpr explicit variant(in_place_type_t<T>, initializer_list<U> il, Args&&... args);-25- […]
[…]
-29- Remarks: IfT
's selected constructor is a constexpr constructor, this constructor is a constexpr constructor.template<size_t I, class... Args> constexpr explicit variant(in_place_index_t<I>, Args&&... args);-30- […]
[…]
-34- Remarks: IfT_{I}
's selected constructor is a constexpr constructor, this constructor is a constexpr constructor.template<size_t I, class U, class... Args> constexpr explicit variant(in_place_index_t<I>, initializer_list<U> il, Args&&... args);-35- […]
[…]
-38- Remarks: IfT_{I}
's selected constructor is a constexpr constructor, this constructor is a constexpr constructor.
Modify 25.5.4.11 [move.sent.ops] as indicated:
constexpr move_sentinel();-1- Effects: Value-initializes
last
.Ifis_trivially_default_constructible_v<S>
istrue
, then this constructor is a constexpr constructor.
Modify 22.15.3 [bit.cast] as indicated:
template<class To, class From> constexpr To bit_cast(const From& from) noexcept;-1- […]
-3- Remarks: This function
iscan be used in a constant expression if and only ifconstexpr
To
,From
, and the types of all subobjects ofTo
and From are typesT
such that:
(3.1) —
is_union_v<T>
isfalse
;(3.2) —
is_pointer_v<T>
isfalse
;(3.3) —
is_member_pointer_v<T>
isfalse
;(3.4) —
is_volatile_v<T>
isfalse
; and(3.5) —
T
has no non-static data members of reference type.
Modify 29.5 [time.duration] as indicated:
-5- The defaulted
copyconstructors of durationshall be a constexpr functioncan be used in a constant expression if and only if the required initialization of the memberrep_
for copy and move, respectively, would satisfy the requirements for a constexpr functioncan be used in a constant expression.