Revised 2012-02-27 at 21:02:54 UTC
Section: 23.4.4.4 [map.modifiers], 23.4.5.3 [multimap.modifiers], X [unord.map.modifiers], X [unord.multimap.modifiers] Status: Tentatively Ready Submitter: P.J. Plauger Opened: 2010-10-14 Last modified: 2012-02-27
View all issues with Tentatively Ready status.
Discussion:
In [unord.map.modifiers], the signature:
template <class P> pair<iterator, bool> insert(P&& obj);
now has an added Remarks paragraph:
Remarks: This signature shall not participate in overload resolution unless P is implicitly convertible to value_type.
The same is true for unordered_multimap.
But neither map nor multimap have this constraint, even though it is a Good Thing(TM) in those cases as well.[ The submitter suggests: Add the same Remarks clause to [map.modifiers] and [multimap.modifiers]. ]
[ 2010-10-29 Daniel comments: ]
I believe both paragraphs need more cleanup: First, the current Requires element conflict with the Remark; second, it seems to me that the whole single Requires element is intended to be split into a Requires and an Effects element; third, the reference to tuple is incorrect (noticed by Paolo Carlini); fourth, it refers to some non-existing InputIterator parameter relevant for a completely different overload; sixth, the return type of the overload with hint is wrong. The following proposed resolution tries to solve these issues as well and uses similar wording as for the corresponding unordered containers. Unfortunately it has some redundancy over Table 99, but I did not remove the specification because of the more general template parameter P - the Table 99 requirements apply only for an argument identical to value_type.
Daniel's Proposed resolution (not current):
- Change 23.4.4.4 [map.modifiers] around p. 1 as indicated:
template <class P> pair<iterator, bool> insert(P&& x); template <class P>pair<iterator, bool>insert(const_iterator position, P&& x);1 Requires:
P shall be convertible tovalue_type is constructible from std::forward<P>(x)..If P is instantiated as a reference type, then the argument x is copied from. Otherwise x is considered to be an rvalue as it is converted to value_type and inserted into the map. Specifically, in such cases CopyConstructible is not required of key_type or mapped_type unless the conversion from P specifically requires it (e.g., if P is a tuple<const key_type, mapped_type>, then key_type must be CopyConstructible). The signature taking InputIterator parameters does not require CopyConstructible of either key_type or mapped_type if the dereferenced InputIterator returns a non-const rvalue pair<key_type,mapped_type>. Otherwise CopyConstructible is required for both key_type and mapped_type.
? Effects: Inserts x converted to value_type if and only if there is no element in the container with key equivalent to the key of value_type(x). For the second form, the iterator position is a hint pointing to where the search should start. ? Returns: For the first form, the bool component of the returned pair object indicates whether the insertion took place and the iterator component - or for the second form the returned iterator - points to the element with key equivalent to the key of value_type(x). ? Complexity: Logarithmic in general, but amortized constant if x is inserted right before position. ? Remarks: These signatures shall not participate in overload resolution unless P is implicitly convertible to value_type.- Change 23.4.5.3 [multimap.modifiers] around p. 1 as indicated:
template <class P> iterator insert(P&& x); template <class P> iterator insert(const_iterator position, P&& x);1 Requires:
P shall be convertible tovalue_type is constructible from std::forward<P>(x).If P is instantiated as a reference type, then the argument x is copied from. Otherwise x is considered to be an rvalue as it is converted to value_type and inserted into the map. Specifically, in such cases CopyConstructible is not required of key_type or mapped_type unless the conversion from P specifically requires it (e.g., if P is a tuple<const key_type, mapped_type>, then key_type must be CopyConstructible). The signature taking InputIterator parameters does not require CopyConstructible of either key_type or mapped_type if the dereferenced InputIterator returns a non-const rvalue pair<key_type, mapped_type>. Otherwise CopyConstructible is required for both key_type and mapped_type.
? Effects: Inserts x converted to value_type. For the second form, the iterator position is a hint pointing to where the search should start. ? Returns: An iterator that points to the element with key equivalent to the key of value_type(x). ? Complexity: Logarithmic in general, but amortized constant if x is inserted right before position. ? Remarks: These signatures shall not participate in overload resolution unless P is implicitly convertible to value_type.
[ 2010 Batavia: ]
We need is_convertible, not is_constructible, both in ordered and unordered containers.
[ 2011 Bloomington ]
The effects of these inserts can be concisely stated in terms of emplace(). Also, the correct term is "EmplaceConstructible", not "constructible".
New wording by Pablo, eliminating duplicate requirements already implied by the effects clause. Move to Review.
[ 2011-10-02 Daniel comments and refines the proposed wording ]
Unfortunately the template constraints expressed as "P is implicitly convertible to value_type" reject the intended effect to support move-only key types, which was the original intention when the library became move-enabled through the rvalue-reference proposals by Howard (This can clearly be deduced from existing carefully selected wording that emphasizes that CopyConstructible is only required for special situations involving lvalues or const rvalues as arguments). The root of the problem is based on current core rules, where an "implicitly converted" value has copy-initialization semantics. Consider a move-only key type KM, some mapped type T, and a source value p of type P equal to std::pair<KM, T>, this is equivalent to:
std::pair<const KM, T> dest = std::move(p);Now 8.5 [dcl.init] p16 b6 sb2 says that the effects of this heterogeneous copy-initialization (p has a different type than dest) are as-if a temporary of the target type std::pair<const KM, T> is produced from the rvalue p of type P (which is fine), and this temporary is used to initialize dest. This second step cannot succeed, because we cannot move from const KM to const KM. This means that std::is_convertible<P, std::pair<const KM, T>>::value is false.
But the actual code that is required (with the default allocator) is simply a direct-initialization from P to value_type, so imposing an implicit conversion is more than necessary. Therefore I strongly recommend to reduce the "overload participation" constraint to std::is_constructible<std::pair<const KM, T>, P>::value instead. This change is the only change that has been performed to the previous proposed wording from Pablo shown below.
[2012, Kona]
Moved to Tentatively Ready by the post-Kona issues processing subgroup, after much discussion on Daniel's analysis of Copy Initialization and move semantics, which we ultimately agreed with.
Proposed resolution:
template <class P> pair<iterator, bool> insert(P&& x); template <class P>pair<iterator, bool>insert(const_iterator position, P&& x);1 Requires: P shall be convertible to value_type.If P is instantiated as a reference type, then the argument x is copied from. Otherwise x is considered to be an rvalue as it is converted to value_type and inserted into the map. Specifically, in such cases CopyConstructible is not required of key_type or mapped_type unless the conversion from P specifically requires it (e.g., if P is a tuple<const key_type, mapped_type>, then key_type must be CopyConstructible). The signature taking InputIterator parameters does not require CopyConstructible of either key_type or mapped_type if the dereferenced InputIterator returns a non-const rvalue pair<key_type,mapped_type>. Otherwise CopyConstructible is required for both key_type and mapped_type.
? Effects: The first form is equivalent to return emplace(std::forward<P>(x)). The second form is equivalent to return emplace_hint(position, std::forward<P>(x)). ? Remarks: These signatures shall not participate in overload resolution unless std::is_constructible<value_type, P&&>::value is true.
template <class P> iterator insert(P&& x); template <class P> iterator insert(const_iterator position, P&& x);1 Requires: P shall be convertible to value_type.If P is instantiated as a reference type, then the argument x is copied from. Otherwise x is considered to be an rvalue as it is converted to value_type and inserted into the map. Specifically, in such cases CopyConstructible is not required of key_type or mapped_type unless the conversion from P specifically requires it (e.g., if P is a tuple<const key_type, mapped_type>, then key_type must be CopyConstructible). The signature taking InputIterator parameters does not require CopyConstructible of either key_type or mapped_type if the dereferenced InputIterator returns a non-const rvalue pair<key_type, mapped_type>. Otherwise CopyConstructible is required for both key_type and mapped_type.
? Effects: The first form is equivalent to return emplace(std::forward<P>(x)). The second form is equivalent to return emplace_hint(position, std::forward<P>(x)). ? Remarks: These signatures shall not participate in overload resolution unless std::is_constructible<value_type, P&&>::value is true.
template <class P> pair<iterator, bool> insert(P&& obj);1 Requires: value_type is constructible from std::forward<P>(obj).2 Effects: equivalent to return emplace(std::forward<P>(obj)).Inserts obj converted to value_type if and only if there is no element in the container with key equivalent to the key of value_type(obj).3 Returns: The bool component of the returned pair object indicates whether the insertion took place and the iterator component points to the element with key equivalent to the key of value_type(obj).4 Complexity: Average case O(1), worst case O(size()).53 Remarks: This signature shall not participate in overload resolution unlessP is implicitly convertible to value_typestd::is_constructible<value_type, P&&>::value is true.template <class P> iterator insert(const_iterator hint, P&& obj);6 Requires: value_type is constructible from std::forward<P>(obj).7? Effects: equivalent to return emplace_hint(hint, std::forward<P>(obj)).Inserts obj converted to value_type if and only if there is no element in the container with key equivalent to the key of value_type(obj). The iterator hint is a hint pointing to where the search should start.8 Returns: An iterator that points to the element with key equivalent to the key of value_type(obj).9 Complexity: Average case O(1), worst case O(size()).10? Remarks: This signature shall not participate in overload resolution unlessP is implicitly convertible to value_typestd::is_constructible<value_type, P&&>::value is true.
template <class P> iterator insert(P&& obj);1 Requires: value_type is constructible from std::forward<P>(obj).2 Effects: equivalent to return emplace(std::forward<P>(obj)).Inserts obj converted to value_type.3 Returns: An iterator that points to the element with key equivalent to the key of value_type(obj).4 Complexity: Average case O(1), worst case O(size()).53 Remarks: This signature shall not participate in overload resolution unlessP is implicitly convertible to value_typestd::is_constructible<value_type, P&&>::value is true.template <class P> iterator insert(const_iterator hint, P&& obj);6 Requires: value_type is constructible from std::forward<P>(obj).7? Effects: equivalent to return emplace_hint(hint, std::forward<P>(obj)).Inserts obj converted to value_type. The iterator hint is a hint pointing to where the search should start.8 Returns: An iterator that points to the element with key equivalent to the key of value_type(obj).9 Complexity: Average case O(1), worst case O(size()).10? Remarks: This signature shall not participate in overload resolution unlessP is implicitly convertible to value_typestd::is_constructible<value_type, P&&>::value is true.
Section: 21.4.8.9 [string.io] Status: Tentatively Ready Submitter: James Kanze Opened: 2010-07-23 Last modified: 2012-02-27
View all other issues in [string.io].
View all issues with Tentatively Ready status.
Discussion:
What should the following code output?
#include <string> #include <iostream> #include <iomanip> int main() { std::string test("0X1Y2Z"); std::cout.fill('*'); std::cout.setf(std::ios::internal, std::ios::adjustfield); std::cout << std::setw(8) << test << std::endl; }
I would expect "**0X1Y2Z", and this is what the compilers I have access to (VC++, g++ and Sun CC) do. But according to the standard, it should be "0X**1Y2Z":
21.4.8.9 [string.io]/5:
template<class charT, class traits, class Allocator> basic_ostream<charT, traits>& operator<<(basic_ostream<charT, traits>& os, const basic_string<charT,traits,Allocator>& str);Effects: Behaves as a formatted output function (27.7.3.6.1 [ostream.formatted.reqmts]). After constructing a sentry object, if this object returns true when converted to a value of type bool, determines padding as described in 22.4.2.2.2 [facet.num.put.virtuals], then inserts the resulting sequence of characters seq as if by calling os.rdbuf()->sputn(seq, n), where n is the larger of os.width() and str.size(); then calls os.width(0).
22.4.2.2.2 [facet.num.put.virtuals]/5:
[…]
Stage 3: A local variable is initialized as
fmtflags adjustfield= (flags & (ios_base::adjustfield));The location of any padding is determined according to Table 88.
If str.width() is nonzero and the number of charT's in the sequence after stage 2 is less than str.width(), then enough fill characters are added to the sequence at the position indicated for padding to bring the length of the sequence to str.width(). str.width(0) is called.
Table 88 — Fill padding State Location adjustfield == ios_base::left pad after adjustfield == ios_base::right pad before adjustfield == internal and a sign occurs in the representation pad after the sign adjustfield == internal and representation after stage 1 began with 0x or 0X pad after x or X otherwise pad before
Although it's not 100% clear what "the sequence after stage 2" should mean here, when there is no stage 2, the only reasonable assumption is that it is the contents of the string being output. In the above code, the string being output is "0X1Y2Z", which starts with "0X", so the padding should be inserted "after x or X", and not before the string. I believe that this is a defect in the standard, and not in the three compilers I tried.
[ 2010 Batavia (post meeting session) ]
Consensus that all known implementations are consistent, and disagree with the standard. Preference is to fix the standard before implementations start trying to conform to the current spec, as the current implementations have the preferred form. Howard volunteered to drught for Madrid, move to Open.
[2011-03-24 Madrid meeting]
Daniel Krügler volunteered to provide wording, interacting with Dietmar and Bill.
[2011-06-24 Daniel comments and provides wording]
The same problem applies to the output provided by const char* and similar character sequences as of 27.7.3.6.4 [ostream.inserters.character] p. 5. and even for single character output (!) as described in 27.7.3.6.4 [ostream.inserters.character] p. 1, just consider the character value '-' where '-' is the sign character. In this case Table 91 — "Fill padding" requires to pad after the sign, i.e. the output for the program
#include <iostream> #include <iomanip> int main() { char c = '-'; std::cout.fill('*'); std::cout.setf(std::ios::internal, std::ios::adjustfield); std::cout << std::setw(2) << c << std::endl; }
According to the current wording this program should output "-*", but all tested implementations output "*-" instead.
I suggest to replace the reference to 22.4.2.2.2 [facet.num.put.virtuals] in all three places. It is not very complicated to describe the padding rules for simple character sequences "inline". A similar approach is used as for the money_put functions.[ 2011 Bloomington ]
Move to Review, the resolution seems correct but it would be nice if some factoring of the common words were proposed.
[2012, Kona]
Moved to Tentatively Ready by the post-Kona issues processing subgroup.
While better factoring of the common words is desirable, it is also editorial and should not hold up the progress of this issue. As the edits impact two distinct clauses, it is not entirely clear what a better factoring should look like.
Proposed resolution:
The new wording refers to the FDIS numbering.
Change 21.4.8.9 [string.io]/5 as indicated:
template<class charT, class traits, class Allocator> basic_ostream<charT, traits>& operator<<(basic_ostream<charT, traits>& os, const basic_string<charT,traits,Allocator>& str);-5- Effects: Behaves as a formatted output function ([ostream.formatted.reqmts]). After constructing a sentry object, if this object returns true when converted to a value of type bool, determines padding as
described in [facet.num.put.virtuals],follows: A charT character sequence is produced, initially consisting of the elements defined by the range [str.begin(), str.end()). If str.size() is less than os.width(), then enough copies of os.fill() are added to this sequence as necessary to pad to a width of os.width() characters. If (os.flags() & ios_base::adjustfield) == ios_base::left is true, the fill characters are placed after the character sequence; otherwise, they are placed before the character sequence. Tthen inserts the resulting sequence of characters seq as if by calling os.rdbuf()->sputn(seq, n), where n is the larger of os.width() and str.size(); then calls os.width(0).
Change 27.7.3.6.4 [ostream.inserters.character]/1 as indicated (An additional editorial fix is suggested for the first prototype declaration):
template<class charT, class traits> basic_ostream<charT,traits>& operator<<(basic_ostream<charT,traits>& out, charT c}); template<class charT, class traits> basic_ostream<charT,traits>& operator<<(basic_ostream<charT,traits>& out, char c); // specialization template<class traits> basic_ostream<char,traits>& operator<<(basic_ostream<char,traits>& out, char c); // signed and unsigned template<class traits> basic_ostream<char,traits>& operator<<(basic_ostream<char,traits>& out, signed char c); template<class traits> basic_ostream<char,traits>& operator<<(basic_ostream<char,traits>& out, unsigned char c);-1- Effects: Behaves like a formatted inserter (as described in [ostream.formatted.reqmts]) of out. After a sentry object is constructed it inserts characters. In case c has type char and the character type of the stream is not char, then the character to be inserted is out.widen(c); otherwise the character is c. Padding is determined as
described in [facet.num.put.virtuals]follows: A character sequence is produced, initially consisting of the insertion character. If out.width() is greater than one, then enough copies of out.fill() are added to this sequence as necessary to pad to a width of out.width() characters. If (out.flags() & ios_base::adjustfield) == ios_base::left is true, the fill characters are placed after the insertion character; otherwise, they are placed before the insertion character.width(0) is called.The insertion character and any required padding are inserted into out; then calls os.width(0).
Change 27.7.3.6.4 [ostream.inserters.character]/5 as indicated:
template<class charT, class traits> basic_ostream<charT,traits>& operator<<(basic_ostream<charT,traits>& out, const charT* s); template<class charT, class traits> basic_ostream<charT,traits>& operator<<(basic_ostream<charT,traits>& out, const char* s); template<class traits> basic_ostream<char,traits>& operator<<(basic_ostream<char,traits>& out, const char* s); template<class traits> basic_ostream<char,traits>& operator<<(basic_ostream<char,traits>& out, const signed char* s); template<class traits> basic_ostream<char,traits>& operator<<(basic_ostream<char,traits>& out, const unsigned char* s);[…]
-5- Padding is determined asdescribed in [facet.num.put.virtuals]. The n characters starting at s are widened using out.widen ([basic.ios.members])follows: A character sequence is produced, initially consisting of the elements defined by the n characters starting at s widened using out.widen ([basic.ios.members]). If n is less than out.width(), then enough copies of out.fill() are added to this sequence as necessary to pad to a width of out.width() characters. If (out.flags() & ios_base::adjustfield) == ios_base::left is true, the fill characters are placed after the character sequence; otherwise, they are placed before the character sequence. The widened characters and any required padding are inserted into out. Calls width(0).
Section: 20.8 [function.objects], 20.8.10 [func.memfn] Status: Tentatively Ready Submitter: Jonathan Wakely Opened: 2011-04-18 Last modified: 2012-02-27
View all other issues in [function.objects].
View all issues with Tentatively Ready status.
Discussion:
The mem_fn overloads for member functions are redundant and misleading and should be removed from the post-C++11 WP.
I believe the history of the overloads is as follows: In TR1 and in C++0x prior to the N2798 draft, mem_fn was specified by a single signature:template<class R, class T> unspecified mem_fn(R T::* pm);
and was accompanied by the remark "Implementations may implement mem_fn as a set of overloaded function templates." This remark predates variadic templates and was presumably to allow implementations to provide overloads for a limited number of function parameters, to meet the implementation-defined limit on numbers of template parameters.
N2770 "Concepts for the C++0x Standard Library: Utilities" added separate overloads for pointers to member functions, apparently so that function parameters would require the CopyConstructible concept (those overloads first appeared in N2322.) The overloads failed to account for varargs member functions (i.e. those declared with an ellipsis in the parameter-declaration-clause) e.g.struct S { int f(int, ...); };
Syntactically such a function would be handled by the original mem_fn(R T::* pm) signature, the only minor drawback being that there would be no CopyConstructible requirement on the parameter list. (Core DR 547 clarifies that partial specializations can be written to match cv-qualified and ref-qualified functions to support the case where R T::* matches a pointer to member function type.)
LWG issue 920 pointed out that additional overloads were missing for member functions with ref-qualifiers. These were not strictly necessary, because such functions are covered by the mem_fn(R T::* pm) signature. Concepts were removed from the draft and N3000 restored the original single signature and accompanying remark. LWG 1230 was opened to strike the remark again and to add an overload for member functions (this overload was unnecessary for syntactic reasons and insufficient as it didn't handle member functions with cv-qualifiers and/or ref-qualifiers.) 920 (and 1230) were resolved by restoring a full set of (non-concept-enabled) overloads for member functions with cv-qualifiers and ref-qualifiers, but as in the concept-enabled draft there were no overloads for member functions with an ellipsis in the parameter-declaration-clause. This is what is present in the FDIS. Following the thread beginning with message c++std-lib-30675, it is my understanding that all the mem_fn overloads for member functions are unnecessary and were only ever added to allow concept requirements. I'm not aware of any reason implementations cannot implement mem_fn as a single function template. Without concepts the overloads are redundant, and the absence of overloads for varargs functions can be interpreted to imply that varargs functions are not intended to work with mem_fn. Clarifying the intent by adding overloads for varargs functions would expand the list of 12 redundant overloads to 24, it would be much simpler to remove the 12 redundant overloads entirely.[Bloomington, 2011]
Move to Review.
The issue and resolution appear to be correct, but there is some concern that the wording of INVOKE may be different depending on whether you pass a pointer-to-member-data or pointer-to-member-function. That might make the current wording necessary after all, and then we might need to add the missing elipsis overloads.
There was some concern that the Remark confirming implementors had freedom to implement this as a set of overloaded functions may need to be restored if we delete the specification for these overloads.
[2012, Kona]
Moved to Tentatively Ready by the post-Kona issues processing subgroup.
Proposed resolution:
This wording is relative to the FDIS.
Change the <functional> synopsis 20.8 [function.objects] p. 2 as follows:
namespace std { […] // [func.memfn], member function adaptors: template<class R, class T> unspecified mem_fn(R T::*);template<class R, class T, class... Args> unspecified mem_fn(R (T::*)(Args...)); template<class R, class T, class... Args> unspecified mem_fn(R (T::*)(Args...) const); template<class R, class T, class... Args> unspecified mem_fn(R (T::*)(Args...) volatile); template<class R, class T, class... Args> unspecified mem_fn(R (T::*)(Args...) const volatile); template<class R, class T, class... Args> unspecified mem_fn(R (T::*)(Args...) &); template<class R, class T, class... Args> unspecified mem_fn(R (T::*)(Args...) const &); template<class R, class T, class... Args> unspecified mem_fn(R (T::*)(Args...) volatile &); template<class R, class T, class... Args> unspecified mem_fn(R (T::*)(Args...) const volatile &); template<class R, class T, class... Args> unspecified mem_fn(R (T::*)(Args...) &&); template<class R, class T, class... Args> unspecified mem_fn(R (T::*)(Args...) const &&); template<class R, class T, class... Args> unspecified mem_fn(R (T::*)(Args...) volatile &&); template<class R, class T, class... Args> unspecified mem_fn(R (T::*)(Args...) const volatile &&);[…] }
Change 20.8.10 [func.memfn] as follows:
template<class R, class T> unspecified mem_fn(R T::*);template<class R, class T, class... Args> unspecified mem_fn(R (T::*)(Args...)); template<class R, class T, class... Args> unspecified mem_fn(R (T::*)(Args...) const); template<class R, class T, class... Args> unspecified mem_fn(R (T::*)(Args...) volatile); template<class R, class T, class... Args> unspecified mem_fn(R (T::*)(Args...) const volatile); template<class R, class T, class... Args> unspecified mem_fn(R (T::*)(Args...) &); template<class R, class T, class... Args> unspecified mem_fn(R (T::*)(Args...) const &); template<class R, class T, class... Args> unspecified mem_fn(R (T::*)(Args...) volatile &); template<class R, class T, class... Args> unspecified mem_fn(R (T::*)(Args...) const volatile &); template<class R, class T, class... Args> unspecified mem_fn(R (T::*)(Args...) &&); template<class R, class T, class... Args> unspecified mem_fn(R (T::*)(Args...) const &&); template<class R, class T, class... Args> unspecified mem_fn(R (T::*)(Args...) volatile &&); template<class R, class T, class... Args> unspecified mem_fn(R (T::*)(Args...) const volatile &&);
Section: 20.9.4.3 [meta.unary.prop] Status: Tentatively Ready Submitter: Daniel Krügler Opened: 2011-04-18 Last modified: 2012-02-27
View other active issues in [meta.unary.prop].
View all other issues in [meta.unary.prop].
View all issues with Tentatively Ready status.
Discussion:
The conditions for the type trait is_destructible to be true are described in Table 49 — Type property predicates:
For a complete type T and given
template <class U> struct test { U u; };,
test<T>::~test() is not deleted.
This specification does not say what the result would be for function types or for abstract types:
which has the same consequence as for abstract types, namely that the corresponding instantiation of test is already ill-formed and we cannot say anything about the destructor.If a declaration acquires a function type through a type dependent on a template-parameter and this causes a declaration that does not use the syntactic form of a function declarator to have function type, the program is ill-formed.
[ Example:template<class T> struct A { static T t; }; typedef int function(); A<function> a; // ill-formed: would declare A<function>::t // as a static member function— end example ]
To solve this problem, I suggest to specify function types as trivially and nothrowing destructible, because above mentioned rule is very special for templates. For non-templates, a typedef can be used to introduce a member as member function as clarified in 8.3.5 [dcl.fct] p. 10.
For abstract types, two different suggestions have been brought to my attention: Either declare them as unconditionally non-destructible or check whether the expression
std::declval<T&>().~T()
is well-formed in an unevaluated context. The first solution is very easy to specify, but the second version has the advantage for providing more information to user-code. This information could be quite useful, if generic code is supposed to invoke the destructor of a reference to a base class indirectly via a delete expression, as suggested by Howard Hinnant:
template <class T> my_pointer<T>::~my_pointer() noexcept(is_nothrow_destructible<T>::value) { delete ptr_; }
Additional to the is_destructible traits, its derived forms is_trivially_destructible and is_nothrow_destructible are similarly affected, because their wording refers to "the indicated destructor" and probably need to be adapted as well.
[ 2011 Bloomington ]
After discussion about to to handle the exceptional cases of reference types, function types (available by defererencing a function pointer) and void types, Howard supplied proposed wording.
[ 2011-08-20 Daniel comments and provides alternatives wording ]
The currently proposed wording would have the consequence that every array type is not destructible, because the pseudo-destructor requires a scalar type with the effect that the expression
std::declval<T&>().~T()
is not well-formed for e.g. T equal to int[3]. The intuitive solution to fix this problem would be to adapt the object type case to refer to the expression
std::declval<U&>().~U()
with U equal to remove_all_extents<T>::type, but that would have the effect that arrays of unknown bounds would be destructible, if the element type is destructible, which was not the case before (This was intentionally covered by the special "For a complete type T" rule in the FDIS).
Suggestion: Use the following definition instead:Let U be remove_all_extents<T>::type.
For incomplete types and function types, is_destructible<T>::value is false.
For object types, if the expression std::declval<U&>().~U() is well-formed
when treated as an unevaluated operand (Clause 5), then is_destructible<T>::value
is true, otherwise it is false.
For reference types, is_destructible<T>::value is true.
This wording also harmonizes with the "unevaluated operand" phrase used in other places, there does not exist the definition of an "unevaluated context"
Note: In the actually proposed wording this wording has been slightly reordered with the same effects.Howard's (old) proposed resolution:
Update 20.9.4.3 [meta.unary.prop], table 49:
template <class T> struct is_destructible; For a complete type T and given template <class U> struct test { U u; };, test<T>::~test() is not deleted.
For object types, if the expression: std::declval<T&>().~T() is well-formed in an unevaluated context then is_destructible<T>::value is true, otherwise it is false.
For void types, is_destructible<T>::value is false.
For reference types, is_destructible<T>::value is true.
For function types, is_destructible<T>::value is false.T shall be a complete type, (possibly cv-qualified) void, or an array of unknown bound.
[2012, Kona]
Moved to Tentatively Ready by the post-Kona issues processing subgroup.
Proposed resolution:
Update 20.9.4.3 [meta.unary.prop], table 49:
template <class T> struct is_destructible; |
For reference types, is_destructible<T>::value is true. For incomplete types and function types, is_destructible<T>::value is false. For object types and given U equal to remove_all_extents<T>::type, if the expression std::declval<U&>().~U() is well-formed when treated as an unevaluated operand (Clause 5 [expr]), then is_destructible<T>::value is true, otherwise it is false. |
T shall be a complete type, (possibly cv-qualified) void, or an array of unknown bound. |
Section: 30.6.1 [futures.overview] Status: Tentatively Ready Submitter: Nicolai Josuttis Opened: 2011-05-18 Last modified: 2012-02-27
View all other issues in [futures.overview].
View all issues with Tentatively Ready status.
Discussion:
In 30.6.1 [futures.overview] enum class future_errc is defined as follows:
enum class future_errc { broken_promise, future_already_retrieved, promise_already_satisfied, no_state };
With this declaration broken_promise has value 0, which means that for a future_error f with this code
f.code().operator bool()
yields false, which makes no sense. 0 has to be reserved for "no error". So, the enums defined here have to start with 1.
Howard, Anthony, and Jonathan have no objections.[Discussion in Bloomington 2011-08-16]
Previous resolution:
This wording is relative to the FDIS.
In 30.6.1 [futures.overview], header <future> synopsis, fix the declaration of future_errc as follows:
namespace std { enum class future_errc {broken_promise,future_already_retrieved = 1, promise_already_satisfied, no_state, broken_promise }; […] }
Is this resolution overspecified? These seem to be all implementation-defined. How do users add new values and not conflict with established error codes?
PJP proxy says: over-specified. boo.
Other error codes: look for is_error_code_enum specializations. Only one exists io_errc
Peter: I don't see any other parts of the standard that specify error codes where we have to do something similar.
Suggest that for every place where we add an error code, the following:
[2012, Kona]
Moved to Tentatively Ready by the post-Kona issues processing subgroup.
Proposed resolution:
This wording is relative to the FDIS.
In 30.6.1 [futures.overview], header <future> synopsis, fix the declaration of future_errc as follows:
namespace std { enum class future_errc { broken_promise = implementation defined, future_already_retrieved = implementation defined, promise_already_satisfied = implementation defined, no_state = implementation defined }; […] }
In 30.6.1 [futures.overview], header <future> synopsis, add a paragraph after paragraph 2 as follows:
The enum values of future_errc are distinct and not zero.Section: 26.6 [numarray] Status: Tentatively Ready Submitter: Gabriel Dos Reis Opened: 2011-05-17 Last modified: 2012-02-27
View all other issues in [numarray].
View all issues with Tentatively Ready status.
Discussion:
It was just brought to my attention that the pair of functions begin/end were added to valarray component. Those additions strike me as counter to the long standing agreement that valarray<T> is not yet another container. Valarray values are in general supposed to be treated as a whole, and as such has a loose specification allowing expression template techniques.
The addition of these functions sound to me as making it much harder (or close to impossible) to effectively use expression templates as implementation techniques, for no clear benefits. My recommendation would be to drop begin/end - or at least for the const valarray<T>& version. I strongly believe those are defects.[This issue was discussed on the library reflector starting from c++std-lib-30761. Some of the key conclusions of this discussion were:]
[ 2011 Bloomington ]
The intent of these overloads is entirely to support the new for syntax, and not to create new containers.
Stefanus provides suggested wording.
[2012, Kona]
Moved to Tenatively Ready by post-meeting issues processing group, after confirmation from Gaby.
Proposed resolution:
In 26.6.1 [valarray.syn]/4, make the following insertion:
4 Implementations introducing such replacement types shall provide additional functions and operators as follows:
In 26.6.10 [valarray.range], make the following insertion:
1 In the begin and end function templates that follow, unspecified1 is a type that meets the requirements of a mutable random access iterator (24.2.7) whose value_type is the template parameter T and whose reference type is T&. unspecified2 is a type that meets the requirements of a constant random access iterator (24.2.7) whose value_type is the template parameter T and whose reference type is const T&.
2 The iterators returned by begin and end for an array are guaranteed to be valid until the member function resize(size_t, T) (26.6.2.8 [valarray.members]) is called for that array or until the lifetime of that array ends, whichever happens first.
Section: 26.5.1.2 [rand.req.seedseq] Status: Tentatively NAD Submitter: Alberto Ganesh Barbati Opened: 2012-01-16 Last modified: 2012-02-27
Discussion:
The seed sequence requirements described in 26.5.1.2 [rand.req.seedseq] appear to be over-specified. All seed sequence types are required to have a result_type nested type, a specific set of constructors, function members size() and param(), which are never used by the library. In fact, the only library components that actively use seed sequences are the random engines and all the engines need is the generate() member function. In particular, library components never attempts to construct seed sequence objects. These extraneous requirements are clearly written to describe the library provided type seed_seq type; while it's good that seed_seq has all those constructors and members, it's not a compelling reason to require a user-provided seed sequence type to implement all of them.
Suppose I want to write my own seed sequence class, this should do fine (and actually works as expected with libc++):class my_seed_seq { /* internals */ public: my_seed_seq(/* my own parameters */); template <class It> void generate(It first, It last); }; my_seed_seq s(/* params */); std::default_random_engine e(s);
The only reason to have these extra members would be to provide some support for generic serializability/persistence of seed sequence objects. I believe that would be out of the scope of the random library, so I doubt we will ever need those requirements in the future.
I therefore propose to remove all requirements from 26.5.1.2 [rand.req.seedseq] except for the presence of the generate() function.[2012, Kona]
Move to Tenatively NAD. (Tentative as issue was not in pre-meeting mailing)
The 'overspecification', as such, was a deliberate intent to provide guarantees consumers of the whole random number framework may rely upon, especially in generic code. While the standard engines may be built without relying on these guarantees, this specification is part of a commitment to a broader framework, and Walter indicated future proposals in preparation for parallel generation of random numbers that may depend more inimately on these existing requirements.
Alisdair noted that the result_type typedef was a call-back to how we used to specify adaptable functors before TR1 result_of and the addition of std::bind and is probably not something we should be actively promoting in future libraries. However, it is too late to remove this requirement from seed sequences unless we are doing further surgery, as recommended by this issue.
Walter notes that the result_type protocol has not been formally deprecated by the standard. Alisdair replies that was the intent of deprecating the bind_1st/ unary_function set of templates in C++11, although we did not say anything about result_type in general.
Proposed resolution:
This wording is relative to the FDIS.
Edit 26.5.1.2 [rand.req.seedseq] p2 as indicated:
A class S satisfies the requirements of a seed sequence if the expressions shown in Table 115 are valid and have the indicated semantics, and if S also satisfies all other requirements of this section 26.5.1.2 [rand.req.seedseq]. In that Table and throughout this section:
T is the type named by S's associated result_type;- q is a value of S
and r is a possibly const value of S; andib and ie are input iterators with an unsigned integer value_type of at least 32 bits;- rb and re are mutable random access iterators with an unsigned integer value_type of at least 32 bits;
ob is an output iterator; andil is a value of initializer_list<T>.
Ditto, in Table 115, remove all rows except the one describing q.generate(rb, re):
Expression | Return type | Pre/Post-condition | Complexity |
---|---|---|---|
|
|
type (3.9.1 [basic.fundamental]) of at least 32 bits. |
|
|
the same initial state as all other default-constructed seed sequences of type S. |
|
|
|
internal state that depends on some or all of the bits of the supplied sequence [ib, ie). |
|
|
|
il.end()). |
S(il.begin(), il.end()) |
|
q.generate(rb,re) | void |
Does nothing if rb == re. Otherwise, fills the supplied sequence [rb, re) with 32-bit quantities that depend on the sequence supplied to the constructor and possibly also depend on the history of generate's previous invocations. |
𝒪(re - rb) |
|
|
would be copied by a call to r.param. |
|
|
|
can be provided to the constructor of a second object of type S, and that would reproduce in that second object a state indistinguishable from the state of the first object. |
|