Revised 2012-11-03 at 04:11:23 UTC

Tentative Issues


2078. Throw specification of async() incomplete

Section: 30.6.8 [futures.async] Status: Tentatively NAD Editorial Submitter: Nicolai Josuttis Opened: 2011-08-29 Last modified: 2012-11-02

View other active issues in [futures.async].

View all other issues in [futures.async].

View all issues with Tentatively NAD Editorial status.

Discussion:

The current throw specification of async() does state:

-6- Throws: system_error if policy is launch::async and the implementation is unable to start a new thread.

First it seems not clear whether this only applies if policy equals launch::async of if the async launch mode flag is set (if policy|launch::async!=0)

In the discussion Lawrence Crowl also wrote:

More generally, I think what we want to say is that if the implementation cannot successfully execute on one of the policies allowed, then it must choose another. The principle would apply to implementation-defined policies as well.

Peter Sommerlad:

Should not throw. That was the intent. "is async" meat exactly.

[2012, Portland: move to Tentatively NAD Editorial]

If no launch policy, it is undefined behavior.

Agree with Lawrence, should try all the allowed policies. We will rephrase so that the policy argument should be lauch::async. Current wording seems good enough.

We believe this choice of policy statement is really an editorial issue.

Proposed resolution:


2080. Specify when once_flag becomes invalid

Section: 30.4.4 [thread.once] Status: Tentatively Ready Submitter: Nicolai Josuttis Opened: 2011-08-30 Last modified: 2012-11-02

View all issues with Tentatively Ready status.

Discussion:

In function call_once 30.4.4.2 [thread.once.callonce] paragraph 4 and 5 specify for call_once():

Throws: system_error when an exception is required (30.2.2 [thread.req.exception]), or any exception thrown by func.

Error conditions:

However, nowhere in 30.4.4 [thread.once] is specified, when a once-flag becomes invalid.

As far as I know this happens if the flag is used for different functions. So we either have to have to insert a sentence/paragraph in

30.4.4.2 Function call_once [thread.once.callonce]

or

30.4.4 Call once [thread.once]

explaining when a once_flag becomes invalidated or we should state as error condition something like:

Anthony Williams:

A once_flag is invalidated if you destroy it (e.g. it is an automatic object, or heap allocated and deleted, etc.)

If the library can detect that this is the case then it will throw this exception. If it cannot detect such a case then it will never be thrown.

Jonathan Wakely:

I have also wondered how that error can happen in C++, where the type system will reject a non-callable type being passed to call_once() and should prevent a once_flag being used after its destructor runs.

If a once_flag is used after its destructor runs then it is indeed undefined behaviour, so implementations are already free to throw any exception (or set fire to a printer) without the standard saying so.

My assumption was that it's an artefact of basing the API on pthreads, which says:

The pthread_once() function may fail if:

[EINVAL] If either once_control or init_routine is invalid.

Pete Becker:

Yes, probably. We had to clean up several UNIXisms that were in the original design.

[2012, Kona]

Remove error conditions, move to Review.

[2012, Portland: move to Tentatively Ready]

Concurrency move to Ready, pending LWG review.

LWG did not have time to perform the final review in Portland, so moving to tentatively ready to reflect the Concurrency belief that the issue is ready, but could use a final inspection from library wordsmiths.

Proposed resolution:

This wording is relative to N3337.

  1. Change 30.4.4.2 [thread.once.callonce] as indicated:

    template<class Callable, class ...Args>
    void call_once(once_flag& flag, Callable&& func, Args&&... args);
    

    […]

    -4- Throws: system_error when an exception is required (30.2.2), or any exception thrown by func.

    -5- Error conditions:

    • invalid_argument — if the once_flag object is no longer valid.

2106. move_iterator wrapping iterators returning prvalues

Section: 24.5.3 [move.iterators] Status: Tentatively Ready Submitter: Dave Abrahams Opened: 2011-11-30 Last modified: 2012-11-02

View all other issues in [move.iterators].

View all issues with Tentatively Ready status.

Discussion:

Shouldn't move_iterator be specialized so that if the iterator it wraps returns a prvalue when dereferenced, the move_iterator also returns by value? Otherwise, it creates a dangling reference.

Howard: I believe just changing move_iterator<I>::reference would do. A direction might be testing on is_reference<iterator_traits<I>::reference>, or is_reference<decltype(*declval<I>())>.

Daniel: I would prefer to use a consistent style among the iterator adaptors, so I suggest to keep with the iterator_traits typedefs if possible.

using reference = typename conditional<
  is_reference<typename iterator_traits<Iterator>::reference>::value,
  value_type&&,
  value_type
>::type;

We might also want to ensure that if Iterator's reference type is a reference, the referent is equal to value_type (after removal of cv-qualifiers). In general we have no such guarantee.

Marc: In the default case where we don't return value_type&&, should we use value_type or should we keep the reference type of the wrapped iterator?

Daniel: This suggestion looks appealing at first, but the problem here is that using this typedef can make it impossible for move_iterator to satisfy its contract, which means returning an rvalue of the value type (Currently it says rvalue-reference, but this must be fixed as of this issue anyway). I think that user-code can reasonably expect that when it has constructed an object m of move_iterator<It>, where It is a valid mutable iterator type, the expression

It::value_type&& rv = *m;

is well-formed.

Let's set R equal to iterator_traits<Iterator>::reference in the following. We can discuss the following situations:

  1. R is a reference type: We can only return the corresponding xvalue of R, if value_type is reference-related to the referent type, else this is presumably no forward iterator and we cannot say much about it, except that it must be convertible to value_type, so it better should return a prvalue.
  2. R is not a reference type: In this case we can rely on a conversion to value_type again, but not much more. Assume we would return R directly, this might turn out to have a conversion to an lvalue-reference type of the value type (for example). If that is the case, this would indirectly violate the contract of move_iterator.

In regard to the first scenario I suggest that implementations are simply required to check that V2 = remove_cv<remove_reference<R>::type>::type is equal to the value type V1 as a criterion to return this reference as an xvalue, in all other cases it should return the value type directly as prvalue.

The additional advantage of this strategy is, that we always ensure that reference has the correct cv-qualification, if R is a real reference.

It is possible to improve this a bit by indeed supporting reference-related types, this would require to test is_same<V1, V2>::value || is_base_of<V1, V2>::value instead. I'm unsure whether (a) this additional effort is worth it and (b) a strict reading of the forward iterator requirements seems not to allow to return a reference-related type (Whether this is a defect or not is another question).

[2011-12-05: Marc Glisse comments and splits into two resolution alternatives]

I guess I am looking at the speed of:

value_type x;
x = *m;

(copy construction would likely trigger copy elision and thus be neutral) instead of the validity of:

value_type&& x = *m;

In this sense, Daniels earlier proposition that ignored value_type and just did switch_lvalue_ref_to_rvalue_ref<reference> was easier to understand (and it didn't require thinking about reference related types).

The currently proposed resolution has been split into two alternatives.

[2012, Kona]

Move to Review.

Alisdair: This only applies to input iterators, so keep that in mind when thinking about this.

STL: I see what B is doing, but not A.

Howard: I agree.

Alisdair: Should we use add_rvalue_reference?

STL: No, we do not want reference collapsing.

STL: Re A, messing with the CV qualification scares me.

Alisdair: Agree. That would break my intent.

STL: Actually I don't think it's actually wrong, but I still don't see what it's doing.

Alisdair: A is picking the value type, B is picking the proxy type.

Howard: I like returning the proxy type.

STL: Returning a reference (B) seems right, because the requirements say "reference". I suspect that B works correctly if you have a move iterator wrapping a move iterator wrapping a thing. I think that A would mess up the type in the middle.

Considerable discussion about which version is correct, checking various examples.

STL: Still think B is right. Still don't understand A. In A we are losing the proxyness.

Howard: Agree 100%. We don't want to lose the proxy. If it's const, so be it.

STL: B is also understandable by mortals.

Howard: Remove to review, keep A but move it out of the proposed resolution area (but keep it for rational).

Alisdair: Adding an explanatory note might be a good idea, if someone wants to write one.

Walter: Concerned about losing the word "reference" in p.1.

Howard: move_iterator will return an xvalue or a prvalue, both of which are rvalues.

[Proposed resolution A, rejected in preference to the currently proposed resolution (B)

  1. Change 24.5.3 [move.iterators] p1 as indicated:

    Class template move_iterator is an iterator adaptor with the same behavior as the underlying iterator except that its dereference operator implicitly converts the value returned by the underlying iterator’s dereference operator to an rvalue referenceof the value type. Some generic algorithms can be called with move iterators to replace copying with moving.

  2. Change 24.5.3.1 [move.iterator], class template move_iterator synopsis, as indicated:

    namespace std {
      template <class Iterator>
      class move_iterator {
      public:
        typedef Iterator iterator_type;
        typedef typename iterator_traits<Iterator>::difference_type difference_type;
        typedef Iterator pointer;
        typedef typename iterator_traits<Iterator>::value_type value_type;
        typedef typename iterator_traits<Iterator>::iterator_category iterator_category;
        typedef value_type&&see below reference;
        […]
      };
    }
    
  3. Immediately following the class template move_iterator synopsis in 24.5.3.1 [move.iterator] insert a new paragraph as indicated:

    -?- Let R be iterator_traits<Iterator>::reference and let V be iterator_traits<Iterator>::value_type. If is_reference<R>::value is true and if remove_cv<remove_reference<R>::type>::type is the same type as V, the template instantiation move_iterator<Iterator> shall define the nested type named reference as a synonym for remove_reference<R>::type&&, otherwise as a synonym for V.

]

[2012, Portland: Move to Tentatively Ready]

AJM wonders if the implied trait might be useful elsewhere, and worth adding to type traits as a transformation type trait.

Suspicion that the Range SG might find such a trait useful, but wait until there is clear additional use of such a trait before standardizing.

Minor wording tweak to use add_rvalue_reference rather than manually adding the &&, then move to Tentatively Ready.

Proposed resolution:

This wording is relative to the FDIS.

This section shows two mutually exclusive resolutions — only one can be picked!

  1. Change 24.5.3 [move.iterators] p1 as indicated:

    Class template move_iterator is an iterator adaptor with the same behavior as the underlying iterator except that its dereference operator implicitly converts the value returned by the underlying iterator’s dereference operator to an rvalue reference. Some generic algorithms can be called with move iterators to replace copying with moving.

  2. Change 24.5.3.1 [move.iterator], class template move_iterator synopsis, as indicated:

    namespace std {
      template <class Iterator>
      class move_iterator {
      public:
        typedef Iterator iterator_type;
        typedef typename iterator_traits<Iterator>::difference_type difference_type;
        typedef Iterator pointer;
        typedef typename iterator_traits<Iterator>::value_type value_type;
        typedef typename iterator_traits<Iterator>::iterator_category iterator_category;
        typedef value_type&&see below reference;
        […]
      };
    }
    
  3. Immediately following the class template move_iterator synopsis in 24.5.3.1 [move.iterator] insert a new paragraph as indicated:

    -?- Let R be iterator_traits<Iterator>::reference. If is_reference<R>::value is true, the template instantiation move_iterator<Iterator> shall define the nested type named reference as a synonym for add_rvalue_reference<R>::type, otherwise as a synonym for R.


2109. Incorrect requirements for hash specializations

Section: 19.5.5 [syserr.hash], 20.7.2.6 [util.smartptr.hash], 20.8.12 [unord.hash], 20.13.1 [type.index.synopsis], 21.6 [basic.string.hash], 23.3.7 [vector.bool], 30.3.1.1 [thread.thread.id] Status: Tentatively Ready Submitter: Daniel Krügler Opened: 2011-12-04 Last modified: 2012-11-02

View all issues with Tentatively Ready status.

Discussion:

20.7.2.6 [util.smartptr.hash] p2 is specified as follows:

Requires: the template specializations shall meet the requirements of class template hash (20.8.12).

The problem here is the usage of a Requires element, which is actually a pre-condition that a user of a component has to satisfy. But the intent of this wording is actually to be a requirement on implementations. The Requires element should be removed here and the wording should be improved to say what it was intended for.

We have similar situations in basically all other places where the specification of library-provided hash specializations is defined. Usually, the Requires element is incorrect. In the special case of hash<unique_ptr<T, D>> the implementation depends on the behaviour of hash specializations, that could be user-provided. In this case the specification needs to separate the requirements on these specializations and those that are imposed on the implementation.

[2012, Kona]

Update wording and move to Review.

Believe a simpler formulation is to simply string the term Requires: and leave the current wording intact, rather than strike the whole clause and replace it.

[Originally proposed wording for reference

  1. Change 19.5.5 [syserr.hash] as indicated:

    template <> struct hash<error_code>;
    

    -1- Requires: the template specialization shall meet the requirements of class template hash (20.8.12 [unord.hash])The header <system_error> provides a definition for a specialization of the template hash<error_code>. The requirements for the members of this specialization are given in sub-clause 20.8.12 [unord.hash].

  2. Change 20.5.3 [bitset.hash] as indicated:

    template <size_t N> struct hash<bitset<N> >;
    

    -1- Requires: the template specialization shall meet the requirements of class template hash (20.8.12 [unord.hash])The header <bitset> provides a definition for a partial specialization of the hash class template for specializations of class template bitset<N>. The requirements for the members of instantiations of this specialization are given in sub-clause 20.8.12 [unord.hash].

  3. Change 20.7.2.6 [util.smartptr.hash] as indicated:

    template <class T, class D> struct hash<unique_ptr<T, D> >;
    

    -1- Requires: the template specialization shall meet the requirements of class template hash (20.8.12 [unord.hash])The header <memory> provides a definition for a partial specialization of the hash class template for specializations of class template unique_ptr<T, D>. The requirements for the members of instantiations of this specialization are given in sub-clause 20.8.12 [unord.hash]. For an object p of type UP, where UP is unique_ptr<T, D>, hash<UP>()(p) shall evaluate to the same value as hash<typename UP::pointer>()(p.get()). The specialization hash<typename UP::pointer> shall be well-formed.

    -?- Requires: The specialization hash<typename UP::pointer> shall be well-formed and well-defined [Note: the general requirements of class template hash (20.8.12 [unord.hash]) are implied — end note].

    template <class T> struct hash<shared_ptr<T> >;
    

    -2- Requires: the template specialization shall meet the requirements of class template hash (20.8.12 [unord.hash])The header <memory> provides a definition for a partial specialization of the hash class template for specializations of class template shared_ptr<T>. The requirements for the members of instantiations of this specialization are given in sub-clause 20.8.12 [unord.hash]. For an object p of type shared_ptr<T>, hash<shared_ptr<T> >()(p) shall evaluate to the same value as hash<T*>()(p.get()).

  4. Change 20.8.12 [unord.hash] p2 as indicated: [Comment: For unknown reasons the extended integer types are not mentioned here, which looks like an oversight to me and makes also the wording more complicated. See 2119 for this part of the problem. — end comment]

    template <> struct hash<bool>;
    template <> struct hash<char>;
    […]
    template <> struct hash<long double>;
    template <class T> struct hash<T*>;
    

    -2- Requires: the template specializations shall meet the requirements of class template hash (20.8.12 [unord.hash])The header <functional> provides definitions for specializations of the hash class template for each cv-unqualified arithmetic type except for the extended integer types. This header also provides a definition for a partial specialization of the hash class template for any pointer type. The requirements for the members of these specializations are given in sub-clause 20.8.12 [unord.hash].

  5. Change 20.13.4 [type.index.hash] p1 as indicated:

    template <> struct hash<type_index>;
    

    -1- Requires: the template specialization shall meet the requirements of class template hash (20.8.12 [unord.hash])The header <typeindex> provides a definition for a specialization of the template hash<type_index>. The requirements for the members of this specialization are given in sub-clause 20.8.12 [unord.hash]. For an object index of type type_index, hash<type_index>()(index) shall evaluate to the same result as index.hash_code().

  6. Change 21.6 [basic.string.hash] p1 as indicated:

    template <> struct hash<string>;
    template <> struct hash<u16string>;
    template <> struct hash<u32string>;
    template <> struct hash<wstring>;
    

    -1- Requires: the template specializations shall meet the requirements of class template hash (20.8.12 [unord.hash])The header <string> provides definitions for specializations of the hash class template for the types string, u16string, u32string, and wstring. The requirements for the members of these specializations are given in sub-clause 20.8.12 [unord.hash].

  7. Change 23.3.7 [vector.bool] p7 as indicated:

    template <class Allocator> struct hash<vector<bool, Allocator> >;
    

    -7- Requires: the template specialization shall meet the requirements of class template hash (20.8.12 [unord.hash])The header <vector> provides a definition for a partial specialization of the hash class template for specializations of class template vector<bool, Allocator>. The requirements for the members of instantiations of this specialization are given in sub-clause 20.8.12 [unord.hash].

  8. Change 30.3.1.1 [thread.thread.id] p14 as indicated:

    template <> struct hash<thread::id>;
    

    -14- Requires: the template specialization shall meet the requirements of class template hash (20.8.12 [unord.hash])The header <thread> provides a definition for a specialization of the template hash<thread::id>. The requirements for the members of this specialization are given in sub-clause 20.8.12 [unord.hash].

]

[2012, Portland: Move to Tentatively Ready]

No further wording issues, so move to Tentatively Ready (post meeting issues processing).

Proposed resolution:

  1. Change 19.5.5 [syserr.hash] as indicated:

    template <> struct hash<error_code>;
    

    -1- Requires: tThe template specialization shall meet the requirements of class template hash (20.8.12 [unord.hash].

  2. Change 20.5.3 [bitset.hash] as indicated:

    template <size_t N> struct hash<bitset<N> >;
    

    -1- Requires: tThe template specialization shall meet the requirements of class template hash (20.8.12 [unord.hash]).

  3. Change 20.7.2.6 [util.smartptr.hash] as indicated:

    template <class T, class D> struct hash<unique_ptr<T, D> >;
    

    -1- Requires: tThe template specialization shall meet the requirements of class template hash (20.8.12 [unord.hash]). For an object p of type UP, where UP is unique_ptr<T, D>, hash<UP>()(p) shall evaluate to the same value as hash<typename UP::pointer>()(p.get()). The specialization hash<typename UP::pointer> shall be well-formed.

    -?- Requires: The specialization hash<typename UP::pointer> shall be well-formed and well-defined, and shall meet the requirements of class template hash (20.8.12 [unord.hash]).

    template <class T> struct hash<shared_ptr<T> >;
    

    -2- Requires: tThe template specialization shall meet the requirements of class template hash (20.8.12 [unord.hash]). For an object p of type shared_ptr<T>, hash<shared_ptr<T> >()(p) shall evaluate to the same value as hash<T*>()(p.get()).

  4. Change 20.8.12 [unord.hash] p2 as indicated: [Comment: For unknown reasons the extended integer types are not mentioned here, which looks like an oversight to me and makes also the wording more complicated. See 2119 for this part of the problem. — end comment]

    template <> struct hash<bool>;
    template <> struct hash<char>;
    […]
    template <> struct hash<long double>;
    template <class T> struct hash<T*>;
    

    -2- Requires: tThe template specializations shall meet the requirements of class template hash (20.8.12 [unord.hash]).

  5. Change 20.13.4 [type.index.hash] p1 as indicated:

    template <> struct hash<type_index>;
    

    -1- Requires: tThe template specialization shall meet the requirements of class template hash (20.8.12 [unord.hash]). For an object index of type type_index, hash<type_index>()(index) shall evaluate to the same result as index.hash_code().

  6. Change 21.6 [basic.string.hash] p1 as indicated:

    template <> struct hash<string>;
    template <> struct hash<u16string>;
    template <> struct hash<u32string>;
    template <> struct hash<wstring>;
    

    -1- Requires: tThe template specializations shall meet the requirements of class template hash (20.8.12 [unord.hash]).

  7. Change 23.3.7 [vector.bool] p7 as indicated:

    template <class Allocator> struct hash<vector<bool, Allocator> >;
    

    -7- Requires: tThe template specialization shall meet the requirements of class template hash (20.8.12 [unord.hash]).

  8. Change 30.3.1.1 [thread.thread.id] p14 as indicated:

    template <> struct hash<thread::id>;
    

    -14- Requires: tThe template specialization shall meet the requirements of class template hash (20.8.12 [unord.hash]).


2125. TimedMutex specification problem

Section: 30.4.1.3 [thread.timedmutex.requirements], 30.4.1.3.1 [thread.timedmutex.class] Status: Tentatively NAD Editorial Submitter: Vicente J. Botet Escriba Opened: 2012-01-01 Last modified: 2012-11-02

View other active issues in [thread.timedmutex.requirements].

View all other issues in [thread.timedmutex.requirements].

View all issues with Tentatively NAD Editorial status.

Discussion:

30.4.1.3.1 [thread.timedmutex.class] says:

The class timed_mutex shall satisfy all of the TimedMutex requirements (30.4.1.3 [thread.timedmutex.requirements]). It shall be a standardlayout class (Clause 9 [class]).

Problem here is that 30.4.1.3 [thread.timedmutex.requirements] does not define a requirement set named "TimedMutex", it only refers to "timed mutex types"

[See also issue 2126]

[2012, Portland: move to Tentatively NAD Editorial]

We have timed mutex type, but it is labeled timed mutex requirements

We can make a suggestion, but will send to the editor as it seems purely editorial. There is a typo, and we don't have the timed mutex but 30.4.1.3 [thread.timedmutex.requirements] already says timed mutex type, and we need to reuse that term down in the class to fulfil the mutex requirement.

[To Editor:]

Replace this one with timed mutex type.

Proposed resolution:


2126. Several specification problems in regard to mutex requirements

Section: 30.4.1 [thread.mutex.requirements], 30.4.1.2.1 [thread.mutex.class], 30.4.1.2 [thread.mutex.requirements.mutex], 30.4.1.2.2 [thread.mutex.recursive], 30.4.1.3 [thread.timedmutex.requirements], 30.4.1.3.1 [thread.timedmutex.class], 30.4.1.3.2 [thread.timedmutex.recursive] Status: Tentatively NAD Editorial Submitter: Pete Becker Opened: 2012-01-16 Last modified: 2012-11-02

View all other issues in [thread.mutex.requirements].

View all issues with Tentatively NAD Editorial status.

Discussion:

30.4.1.2.1 [thread.mutex.class]/3 says that the class mutex "shall satisfy all the Mutex requirements (30.4.1 [thread.mutex.requirements])". 30.4.1.2.1 [thread.mutex.class] is part of 30.4.1 [thread.mutex.requirements], so at the very least, this requirement is recursive. But worse, there is nothing that says what "the Mutex requirements" refers to. For example, the "Lockable requirements" section starts with "A type L meets the Lockable requirements if …". There is no such statement for "the Mutex requirements".

Organizationally, paragraphs 1-26 in 30.4.1.2 [thread.mutex.requirements.mutex] should probably be in a subclause with a name. (This is actually an ISO requirement, to avoid exactly this kind of ambiguous referencing) Then the first sentence of 30.4.1.2.1 [thread.mutex.class]/3 can become a note: "The class mutex meets the requirements of (whatever)", since that subclause already says that the mutex types "shall meet the requirements set out in this section."

And similarly for 30.4.1.2.2 [thread.mutex.recursive]/2 (recursive_mutex).

30.4.1.3 [thread.timedmutex.requirements], Timed mutex types, also needs the same rearrangement: its introductory requirements should be moved into a subclause, and the first sentences of 30.4.1.3.1 [thread.timedmutex.class]/2 and 30.4.1.3.2 [thread.timedmutex.recursive]/2 should be turned into notes that refer to this new subclause and to the new subclause in 30.4.1.2 [thread.mutex.requirements.mutex].

[See also issue 2125]

[2012, Portland: move to Tentatively NAD Editorial]

Seems no real ambiguity. May need some reorg of text rather then changing the wording.

Is there much that needs to be changed? But Pete's suggestion of putting requirement in separate sub section is good. Should be the direction to editor.

Suggest this is an editorial change. Happy with Pete's comments.

Proposed resolution:


2134. Redundant Mutex requirement?

Section: 30.4.1.2 [thread.mutex.requirements.mutex] Status: Tentatively NAD Editorial Submitter: Pete Becker Opened: 2012-03-05 Last modified: 2012-11-02

View all other issues in [thread.mutex.requirements.mutex].

View all issues with Tentatively NAD Editorial status.

Discussion:

30.4.1.2 [thread.mutex.requirements.mutex]/11 says that prior unlock operations synchronize with m.lock().

30.4.1.2 [thread.mutex.requirements.mutex]/19 says that if m.try_lock() succeeds, prior unlock operations synchronize with the operation.

30.4.1.2 [thread.mutex.requirements.mutex]/25 says that m.unlock() synchronizes with subsequent successful lock operations.

Does the third requirement add anything to the first two? If not, it should probably be a non-normative note.

[2012, Portland: move to Tentatively NAD Editorial]

Agree that third note should be non-normative and adds nothing.

Seems An Editorial change, but does changing a normative to non-normative wording makes it a non-editorial change?

Ask the editor. If not editorial, then we will agree on the fix as removal of the third point, then we will put it in ready state for Bristol.

Proposed resolution:


2167. Copy assignment requirements of Containers

Section: 23.2.1 [container.requirements.general] Status: Tentatively NAD Submitter: Dean Michael Berris Opened: 2012-07-13 Last modified: 2012-11-02

View other active issues in [container.requirements.general].

View all other issues in [container.requirements.general].

Discussion:

Table 96 defines the general requirement for copy assignment (row 23, page 704) as:

Table 96 — Container requirements
Expression Return type Operational semantics Assertion/note pre-/post-condition Complexity
r = a X& post: r == a. linear

However there is no requirement that T is CopyInsertable into X.

[2012, Portland: Move to Tentatively NAD]

Howard notes that this may be a difficult requirement for std::array

We already have this requirement for allocator aware containers, and std::array already adds the appropriate extra requirement.

We say the necessary things in the necessary places, but the container requirements continue to cause confusion in where we sometimes say things. Consensus is that this issue remains NAD though.

Proposed resolution:

This wording is relative to N3376.

  1. Change Table 96 — "Container requirements" in 23.2.1 [container.requirements.general]:

    Table 96 — Container requirements
    Expression Return type Operational semantics Assertion/note pre-/post-condition Complexity
    r = a X& Requires: T is CopyInsertable into X.
    post: r == a.
    linear

2177. Requirements on Copy/MoveInsertable

Section: 23.2.1 [container.requirements.general] Status: Tentatively Ready Submitter: Loïc Joly Opened: 2012-08-10 Last modified: 2012-11-02

View other active issues in [container.requirements.general].

View all other issues in [container.requirements.general].

View all issues with Tentatively Ready status.

Discussion:

See also discussion following c++std-lib-32883 and c++std-lib-32897.

The requirements on CopyInsertable and MoveInsertable are either incomplete, or complete but hard to figure out.

From e-mail c++std-lib-32897:

Pablo Halpern:

I agree that we need semantic requirements for all of the *Insertable concepts analogous to the requirements we have on similar concepts.

Howard Hinnant:

I've come to believe that the standard is actually correct as written in this area. But it is really hard to read. I would have no objection whatsoever to clarifications to CopyInsertable as you suggest (such as the post-conditions on v). And I do agree with you that the correct approach to the clarifications is to confirm that CopyInsertable implies MoveInsertable.

[2012, Portland: Move to Tentatively Ready]

Move to Tentatively Ready by unanimous consent.

Proposed resolution:

This wording is relative to N3376.

  1. Edit 23.2.1 [container.requirements.general] p13 as indicated:

    -13- […] Given a container type X having an allocator_type identical to A and a value_type identical to T and given an lvalue m of type A, a pointer p of type T*, an expression v of type (possibly const) T, and an rvalue rv of type T, the following terms are defined. If X is not allocator-aware, the terms below are defined as if A were std::allocator<T> — no allocator object needs to be created and user specializations of std::allocator<T> are not instantiated:

    • T is DefaultInsertable into X means that the following expression is well-formed:

      allocator_traits<A>::construct(m, p);
      
    • An element of X is default-inserted if it is initialized by evaluation of the expression

      allocator_traits<A>::construct(m, p);
      

      where p is the address of the uninitialized storage for the element allocated within X.

    • T is CopyMoveInsertable into X means that the following expression is well-formed:

      allocator_traits<A>::construct(m, p, rv);
      

      and when evaluated the following postconditions hold: The value of *p is equivalent to the value of rv before the evaluation. [Note: rv remains a valid object. Its state is unspecified — end note]

    • T is MoveCopyInsertable into X means that, in addition to satisfying the MoveInsertable requirements, the following expression is well-formed:

      allocator_traits<A>::construct(m, p, rv);
      

      and when evaluated the following postconditions hold: The value of v is unchanged and is equivalent to *p.

    • T is EmplaceConstructible into X from args, for zero or more arguments args, means that the following expression is well-formed:

      allocator_traits<A>::construct(m, p, args);
      
    • T is Erasable from X means that the following expression is well-formed:

      allocator_traits<A>::destroy(m, p);
      

    [Note: A container calls allocator_traits<A>::construct(m, p, args) to construct an element at p using args. The default construct in std::allocator will call ::new((void*)p) T(args), but specialized allocators may choose a different definition. — end note]


2187. vector<bool> is missing emplace and emplace_back member functions

Section: 23.3.7 [vector.bool] Status: Tentatively Ready Submitter: Nevin Liber Opened: 2012-09-21 Last modified: 2012-11-02

View all other issues in [vector.bool].

View all issues with Tentatively Ready status.

Discussion:

It should have them so that it more closely matches the vector<T> interface, as this helps when writing generic code.

[2012, Portland: Move to Tentatively Ready]

Question on whether the variadic template is really needed, but it turns out to be needed to support emplace of no arguments.

Proposed resolution:

This wording is relative to N3376.

  1. Change the class template vector<bool> synopsis, 23.3.7 [vector.bool] p1, as indicated:

    namespace std {
      template <class Allocator> class vector<bool, Allocator> {
      public:
        […]
        // modifiers:
        template <class... Args> void emplace_back(Args&&... args);
        void push_back(const bool& x);
        void pop_back();
        template <class... Args> iterator emplace(const_iterator position, Args&&... args);
        iterator insert(const_iterator position, const bool& x);
        […]
      };
    }