This page is a snapshot from the LWG issues list, see the Library Active Issues List for more information and the meaning of C++17 status.
Section: 29.5.3.2 [rand.req.seedseq], 29.5.4 [rand.eng], 29.5.5 [rand.adapt] Status: C++17 Submitter: Daniel Krügler Opened: 2012-08-18 Last modified: 2017-07-30
Priority: 3
View all other issues in [rand.req.seedseq].
View all issues with C++17 status.
Discussion:
LWG issue 2180(i) points out some deficiences in regard to the specification of the library-provided
type std::seed_seq
regarding exceptions, but there is another specification problem
in regard to general types satisfying the seed sequence constraints (named SSeq
) as described in
29.5.3.2 [rand.req.seedseq].
Except where specified otherwise, no function described in this section 29.5.4 [rand.eng]/29.5.5 [rand.adapt] throws an exception.
This constraint causes problems, because the described templates in these sub-clauses depend on operations of
SSeq::generate()
which is a function template, that depends both on operations provided by the
implementor of SSeq
(e.g. of std::seed_seq
), and those of the random access iterator type
provided by the caller. With class template linear_congruential_engine
we have just one example for a user
of SSeq::generate()
via:
template<class Sseq> linear_congruential_engine<>::linear_congruential_engine(Sseq& q); template<class Sseq> void linear_congruential_engine<>::seed(Sseq& q);
None of these operations has an exclusion rule for exceptions.
As described in 2180(i) the wording forstd::seed_seq
should and can be fixed to ensure that
operations of seed_seq::generate()
won't throw except from operations of the provided iterator range,
but there is no corresponding "safety belt" for user-provided SSeq
types, since 29.5.3.2 [rand.req.seedseq]
does not impose no-throw requirements onto operations of seed sequences.
A quite radical step to fix this problem would be to impose general no-throw requirements on the expression
q.generate(rb,re)
from Table 115, but this is not as simple as it looks initially, because this
function again depends on general types that are mutable random access iterators. Typically, we do not
impose no-throw requirements on iterator operations and this would restrict general seed sequences where
exceptions are not a problem. Furthermore, we do not impose comparable constraints for other expressions,
like that of the expression g()
in Table 116 for good reasons, e.g. random_device::operator()
explicitly states when it throws exceptions.
A less radical variant of the previous suggestion would be to add a normative requirement on the expression
q.generate(rb,re)
from Table 115 that says: "Throws nothing if operations of rb
and re
do not throw exceptions". Nevertheless we typically do not describe conditional Throws elements in proper
requirement sets elsewhere (Container requirements excluded, they just describe the containers from Clause 23)
and this may exclude resonable implementations of seed sequences that could throw exceptions under rare
situations.
The iterator arguments provided to SSeq::generate()
for operations in templates of 29.5.4 [rand.eng] and
29.5.5 [rand.adapt] are under control of implementations, so we could impose stricter exceptions requirements
on SSeq::generate()
for SSeq
types that are used to instantiate member templates in 29.5.4 [rand.eng]
and 29.5.5 [rand.adapt] solely.
We simply add extra wording to the introductive parts of 29.5.4 [rand.eng] and 29.5.5 [rand.adapt]
that specify that operations of the engine (adaptor) templates that depend on a template parameter SSeq
throw no exception unless SSeq::generate()
throws an exception.
Given these options I would suggest to apply the variant described in the fourth bullet.
The proposed resolution attempts to reduce a lot of the redundancies of requirements in the introductory paragraphs of 29.5.4 [rand.eng] and 29.5.5 [rand.adapt] by introducing a new intermediate sub-clause "Engine and engine adaptor class templates" following sub-clause 29.5.2 [rand.synopsis]. This approach also solves the problem that currently 29.5.4 [rand.eng] also describes requirements that apply for 29.5.5 [rand.adapt] (Constrained templates involving theSseq
parameters).
[2013-04-20, Bristol]
Remove the first bullet point:
?- Throughout this sub-clause general requirements and conventions are described that apply to every class template specified in sub-clause 29.5.4 [rand.eng] and 29.5.5 [rand.adapt]. Phrases of the form "in those sub-clauses" shall be interpreted as equivalent to "in sub-clauses 29.5.4 [rand.eng] and 29.5.5 [rand.adapt]".
Replace "in those sub-clauses" with "in sub-clauses 29.5.4 [rand.eng] and 29.5.5 [rand.adapt]".
Find another place for the wording. Daniel: These are requirements on the implementation not on the types. I'm not comfortable in moving it to another place without double checking. Improve the text (there are 4 "for"s): for copy constructors, for copy assignment operators, for streaming operators, and for equality and inequality operators are not shown in the synopses. Move the information of this paragraph to the paragraphs it refers to:"-?- Descriptions are provided in those sub-clauses only for engine operations that are not described in 29.5.3.4 [rand.req.eng], for adaptor operations that are not described in 29.5.3.5 [rand.req.adapt], or for operations where there is additional semantic information. In particular, declarations for copy constructors, for copy assignment operators, for streaming operators, and for equality and inequality operators are not shown in the synopses."
Alisdair: I prefer duplication here than consolidation/reference to these paragraphs.
The room showed weakly favjust or for duplication.Previous resolution from Daniel [SUPERSEDED]:
Add a new sub-clause titled "Engine and engine adaptor class templates" following sub-clause 29.5.2 [rand.synopsis] (but at the same level) and add one further sub-clause "General" as child of the new sub-clause as follows:
Engine and engine adaptor class templates [rand.engadapt] General [rand.engadapt.general]-?- Throughout this sub-clause general requirements and conventions are described that apply to every class template specified in sub-clause 29.5.4 [rand.eng] and 29.5.5 [rand.adapt]. Phrases of the form "in those sub-clauses" shall be interpreted as equivalent to "in sub-clauses 29.5.4 [rand.eng] and 29.5.5 [rand.adapt]".
-?- Except where specified otherwise, the complexity of each function specified in those sub-clauses is constant. -?- Except where specified otherwise, no function described in those sub-clauses throws an exception. -?- Every function described in those sub-clauses that has a function parameterq
of typeSSeq&
for a template type parameter namedSSeq
that is different from typestd::seed_seq
throws what and when the invocation ofq.generate
throws. -?- Descriptions are provided in those sub-clauses only for engine operations that are not described in 29.5.3.4 [rand.req.eng], for adaptor operations that are not described in 29.5.3.5 [rand.req.adapt], or for operations where there is additional semantic information. In particular, declarations for copy constructors, for copy assignment operators, for streaming operators, and for equality and inequality operators are not shown in the synopses. -?- Each template specified in those sub-clauses requires one or more relationships, involving the value(s) of its non-type template parameter(s), to hold. A program instantiating any of these templates is ill-formed if any such required relationship fails to hold. -?- For every random number engine and for every random number engine adaptorX
defined in those sub-clauses:
if the constructor
template <class Sseq> explicit X(Sseq& q);is called with a type
Sseq
that does not qualify as a seed sequence, then this constructor shall not participate in overload resolution;if the member function
template <class Sseq> void seed(Sseq& q);is called with a type
Sseq
that does not qualify as a seed sequence, then this function shall not participate in overload resolution;The extent to which an implementation determines that a type cannot be a seed sequence is unspecified, except that as a minimum a type shall not qualify as a seed sequence if it is implicitly convertible to
X::result_type
.Edit the contents of sub-clause 29.5.4 [rand.eng] as indicated:
-1- Each type instantiated from a class template specified in this section 29.5.4 [rand.eng] satisfies the requirements of a random number engine (29.5.3.4 [rand.req.eng]) type and the general implementation requirements specified in sub-clause [rand.engadapt.general].
-2- Except where specified otherwise, the complexity of each function specified in this section 29.5.4 [rand.eng] is constant.-3- Except where specified otherwise, no function described in this section 29.5.4 [rand.eng] throws an exception.-4- Descriptions are provided in this section 29.5.4 [rand.eng] only for engine operations that are not described in 29.5.3.4 [rand.req.eng] […]-5- Each template specified in this section 29.5.4 [rand.eng] requires one or more relationships, involving the value(s) of its non-type template parameter(s), to hold. […]-6- For every random number engine and for every random number engine adaptorX
defined in this subclause (29.5.4 [rand.eng]) and in sub-clause 29.5.4 [rand.eng]: […]Edit the contents of sub-clause 29.5.5.1 [rand.adapt.general] as indicated:
-1- Each type instantiated from a class template specified in this section
29.5.4 [rand.eng]29.5.5 [rand.adapt] satisfies the requirements of a random number engine adaptor (29.5.3.5 [rand.req.adapt]) type and the general implementation requirements specified in sub-clause [rand.engadapt.general].-2- Except where specified otherwise, the complexity of each function specified in this section 29.5.5 [rand.adapt] is constant.-3- Except where specified otherwise, no function described in this section 29.5.5 [rand.adapt] throws an exception.-4- Descriptions are provided in this section 29.5.5 [rand.adapt] only for engine operations that are not described in 29.5.3.5 [rand.req.adapt] […]-5- Each template specified in this section 29.5.5 [rand.adapt] requires one or more relationships, involving the value(s) of its non-type template parameter(s), to hold. […]
[2014-02-09, Daniel provides alternative resolution]
[Lenexa 2015-05-07: Move to Ready]
LWG 2181 exceptions from seed sequence operations
STL: Daniel explained that I was confused. I said, oh, seed_seq says it can throw if the RanIt throws. Daniel says the RanIts are provided by the engine. Therefore if you give a seed_seq to an engine, it cannot throw, as implied by the current normative text. So what Daniel has in the PR is correct, if slightly unnecessary. It's okay to have explicitly non-overlapping Standardese even if overlapping would be okay.
Marshall: And this is a case where the std:: on seed_seq is a good thing.
STL: Meh.
STL: And that was my only concern with this PR. I like the latest PR much better than the previous.
Marshall: Yes. There's a drive-by fix for referencing the wrong section. Other than that, the two are the same.
STL: Alisdair wanted the repetition instead of centralization, and I agree.
Marshall: Any other opinions?
Jonathan: I'll buy it.
STL: For a dollar?
Hwrd: I'll buy that for a nickel.
Marshall: Any objections to Ready? I don't see a point in Immediate.
Jonathan: Absolutely agree.
Marshall: 7 for ready, 0 opposed, 0 abstain.
[2014-05-22, Daniel syncs with recent WP]
[2015-10-31, Daniel comments and simplifies suggested wording changes]
Upon Walter Brown's suggestion the revised wording does not contain any wording changes that could be considered as editorial.
Previous resolution from Daniel [SUPERSEDED]:
This wording is relative to N3936.
Edit the contents of sub-clause 29.5.4 [rand.eng] as indicated:
-1- Each type instantiated from a class template specified in this section 29.5.4 [rand.eng] satisfies the requirements of a random number engine (29.5.3.4 [rand.req.eng]) type.
-2- Except where specified otherwise, the complexity of each function specified in this section 29.5.4 [rand.eng] is constant. -3- Except where specified otherwise, no function described in this section 29.5.4 [rand.eng] throws an exception. -?- Every function described in this section 29.5.4 [rand.eng] that has a function parameterq
of typeSseq&
for a template type parameter namedSseq
that is different from typestd::seed_seq
throws what and when the invocation ofq.generate
throws. -4- Descriptions are provided in this section 29.5.4 [rand.eng] only for engine operations that are not described in 29.5.3.4 [rand.req.eng] or for operations where there is additional semantic information. In particular, declarations for copy constructors,forcopy assignment operators,forstreaming operators,and forequality operators, and inequality operators are not shown in the synopses. -5- Each template specified in this section 29.5.4 [rand.eng] requires one or more relationships, involving the value(s) of its non-type template parameter(s), to hold. A program instantiating any of these templates is ill-formed if any such required relationship fails to hold. -6- For every random number engine and for every random number engine adaptorX
defined in this subclause (29.5.4 [rand.eng]) and in sub-clause 29.5.5 [rand.adapt]:
if the constructor
template <class Sseq> explicit X(Sseq& q);is called with a type
Sseq
that does not qualify as a seed sequence, then this constructor shall not participate in overload resolution;if the member function
template <class Sseq> void seed(Sseq& q);is called with a type
Sseq
that does not qualify as a seed sequence, then this function shall not participate in overload resolution;The extent to which an implementation determines that a type cannot be a seed sequence is unspecified, except that as a minimum a type shall not qualify as a seed sequence if it is implicitly convertible to
X::result_type
.Edit the contents of sub-clause 29.5.5.1 [rand.adapt.general] as indicated:
-1- Each type instantiated from a class template specified in this section
-2- Except where specified otherwise, the complexity of each function specified in this section 29.5.5 [rand.adapt] is constant. -3- Except where specified otherwise, no function described in this section 29.5.5 [rand.adapt] throws an exception. -?- Every function described in this section 29.5.5 [rand.adapt] that has a function parameter29.5.4 [rand.eng]29.5.5 [rand.adapt] satisfies the requirements of a random number engine adaptor (29.5.3.5 [rand.req.adapt]) type.q
of typeSseq&
for a template type parameter namedSseq
that is different from typestd::seed_seq
throws what and when the invocation ofq.generate
throws. -4- Descriptions are provided in this section 29.5.5 [rand.adapt] only for adaptor operations that are not described in section 29.5.3.5 [rand.req.adapt] or for operations where there is additional semantic information. In particular, declarations for copy constructors,forcopy assignment operators,forstreaming operators,and forequality operators, and inequality operators are not shown in the synopses. -5- Each template specified in this section 29.5.5 [rand.adapt] requires one or more relationships, involving the value(s) of its non-type template parameter(s), to hold. A program instantiating any of these templates is ill-formed if any such required relationship fails to hold.Edit the contents of sub-clause 29.5.9.1 [rand.dist.general] p2 as indicated: [Drafting note: These editorial changes are just for consistency with those applied to 29.5.4 [rand.eng] and 29.5.5.1 [rand.adapt.general] — end drafting note]
-2- Descriptions are provided in this section 29.5.9 [rand.dist] only for distribution operations that are not described in 29.5.3.6 [rand.req.dist] or for operations where there is additional semantic information. In particular, declarations for copy constructors,
forcopy assignment operators,forstreaming operators,and forequality operators, and inequality operators are not shown in the synopses.
Proposed resolution:
This wording is relative to N4527.
Edit the contents of sub-clause 29.5.4 [rand.eng] as indicated:
-1- […]
-2- Except where specified otherwise, the complexity of each function specified in this section 29.5.4 [rand.eng] is constant. -3- Except where specified otherwise, no function described in this section 29.5.4 [rand.eng] throws an exception. -?- Every function described in this section 29.5.4 [rand.eng] that has a function parameterq
of typeSseq&
for a template type parameter namedSseq
that is different from typestd::seed_seq
throws what and when the invocation ofq.generate
throws. […]
Edit the contents of sub-clause 29.5.5.1 [rand.adapt.general] as indicated:
-1- […]
-2- Except where specified otherwise, the complexity of each function specified in this section 29.5.5 [rand.adapt] is constant. -3- Except where specified otherwise, no function described in this section 29.5.5 [rand.adapt] throws an exception. -?- Every function described in this section 29.5.5 [rand.adapt] that has a function parameterq
of typeSseq&
for a template type parameter namedSseq
that is different from typestd::seed_seq
throws what and when the invocation ofq.generate
throws.