Doc. no. | R0165??? |
Date: | Revised 2016-11-28 at 15:11:14 UTC |
Project: | Programming Language C++ |
Reply to: | Marshall Clow <lwgchair@gmail.com> |
Section: 17.5.3.5 [allocator.requirements] Status: Tentatively Ready Submitter: Jonathan Wakely Opened: 2013-05-14 Last modified: 2016-11-28
Priority: 3
View other active issues in [allocator.requirements].
View all other issues in [allocator.requirements].
View all issues with Tentatively Ready status.
Discussion:
For an allocator A<T> which defines A<T>::pointer to a class type, i.e. not T*, I see no requirement that A<T>::pointer is convertible to A<U>::pointer, even if T* is convertible to U*. Such conversions are needed in containers to convert from e.g. ListNodeBase* to ListNode<T>*.
The obvious way to do such conversions appears to be pointer_traits::pointer_to(), but that's ill-formed if the static member function A<T>::pointer::pointer_to() doesn't exist and the allocator requirements don't mention that function, so you need to cast A<T>::pointer to A<T>::void_pointer then cast that to A<U>::pointer.
Is converting via void_pointer really intended, or are we missing a requirement that pointer_traits<A<T>::pointer>::pointer_to() be well-formed?
Proposed resolution:
Add to the Allocator requirements table the following requirement:
The expression pointer_traits<XX::pointer>::pointer_to(r) is well-defined.
[2013-09 Chicago]
Pablo to come back with proposed wording
[2015-07 Telecom]
Marshall to ping Pablo for proposed wording and disable current wording.
Previous resolution [SUPERSEDED]:
Edit Table 28 as indicated:
Table 28 — Allocator requirements (continued) Expression Return type Assertion/note pre-/post-condition Default … static_cast<X::const_pointer>(z) X::const_pointer static_cast<X::const_pointer>(z) == q pointer_traits<X::pointer>::pointer_to(r) X::pointer …
[2016-11-12, Issaquah]
This is related to 1521.
Sat PM: Restore original P/R and move to tentatively ready.
Proposed resolution:
Edit Table 28 as indicated:
Table 28 — Allocator requirements (continued) Expression Return type Assertion/note pre-/post-condition Default … static_cast<X::const_pointer>(z) X::const_pointer static_cast<X::const_pointer>(z) == q pointer_traits<X::pointer>::pointer_to(r) X::pointer …
Section: 20.14.12.2.1 [func.wrap.func.con] Status: Ready Submitter: Jonathan Wakely Opened: 2016-10-13 Last modified: 2016-11-28
Priority: 0
View other active issues in [func.wrap.func.con].
View all other issues in [func.wrap.func.con].
View all issues with Ready status.
Discussion:
template<class F> function(F f) says that the effects are "*this targets a copy of f" which seems pretty clear that if F is reference_wrapper<CallableType> then the target is a reference_wrapper<CallableType>.
But the function copy and move constructors say "shall not throw exceptions if f's target is a callable object passed via reference_wrapper or a function pointer." From the requirement above it's impossible for the target to be "a callable object passed via reference_wrapper" because if the function was constructed with such a type then the target is the reference_wrapper not the callable object it wraps. This matters because it affects the result of function::target_type(), and we have implementation divergence. VC++ and libc++ store the reference_wrapper as the target, but libstdc++ and Boost.Function (both written by Doug Gregor) unwrap it, so the following fails:#include <functional> #include <cassert> int main() { auto f = []{}; std::function<void()> fn(std::ref(f)); assert(fn.target<std::reference_wrapper<decltype(f)>>() != nullptr); }
If std::function is intended to deviate from boost::function this way then the Throws element for the copy and move constructors is misleading, and should be clarified.
[2016-11-12, Issaquah]
Sat AM: Priority 0; move to Ready
Proposed resolution:
This wording is relative to N4606.
Modify 20.14.12.2.1 [func.wrap.func.con] p4 and p6 the same way, as shown:
function(const function& f);-3- Postconditions: !*this if !f; otherwise, *this targets a copy of f.target().
-4- Throws: shall not throw exceptions if f's target is acallable object passed viaspecialization of reference_wrapper or a function pointer. Otherwise, may throw bad_alloc or any exception thrown by the copy constructor of the stored callable object. [Note: Implementations are encouraged to avoid the use of dynamically allocated memory for small callable objects, for example, where f's target is an object holding only a pointer or reference to an object and a member function pointer. — end note]function(function&& f);-5- Effects: If !f, *this has no target; otherwise, move constructs the target of f into the target of *this, leaving f in a valid state with an unspecified value.
-6- Throws: shall not throw exceptions if f's target is acallable object passed viaspecialization of reference_wrapper or a function pointer. Otherwise, may throw bad_alloc or any exception thrown by the copy or move constructor of the stored callable object. [Note: Implementations are encouraged to avoid the use of dynamically allocated memory for small callable objects, for example, where f's target is an object holding only a pointer or reference to an object and a member function pointer. — end note]
Section: 20.13.3 [allocator.adaptor.cnstr] Status: Ready Submitter: Jonathan Wakely Opened: 2016-10-14 Last modified: 2016-11-28
Priority: 0
View all issues with Ready status.
Discussion:
The templated constructors of scoped_allocator_adaptor need to be constrained, otherwise uses-allocator construction gives the wrong answer and causes errors for code that should compile.
Consider two incompatible allocator types:template<class T> struct Alloc1 { ... }; template<class T> struct Alloc2 { ... }; static_assert(!is_convertible_v<Alloc1<int>, Alloc2<int>>);
The unconstrained constructors give this bogus answer:
template<class T> using scoped = scoped_allocator_adaptor<T>; static_assert(is_convertible_v<scoped<Alloc1<int>>, scoped<Alloc2<int>>>);
This causes uses_allocator to give the wrong answer for any specialization involving incompatible scoped_allocator_adaptors, which makes scoped_allocator_adaptor::construct() take an ill-formed branch e.g.
struct X { using allocator_type = scoped<Alloc2<int>>; X(const allocator_type&); X(); }; scoped<Alloc1<int>>{}.construct((X*)0);
This fails to compile, because uses_allocator<X, scoped_allocator_adaptor<Alloc2<int>>> is true, so the allocator is passed to the X constructor, but the conversion fails. The error is outside the immediate context, and so is a hard error.
[2016-11-12, Issaquah]
Sat AM: Priority 0; move to Ready
Billy to open another issue about the confusion with the ctor
Proposed resolution:
This wording is relative to N4606.
Modify 20.13.3 [allocator.adaptor.cnstr] by converting "Requires" elements to "Remarks: shall not participate ..." constraints as shown:
template <class OuterA2> scoped_allocator_adaptor(OuterA2&& outerAlloc, const InnerAllocs&... innerAllocs) noexcept;-3- Effects: Initializes the OuterAlloc base class with std::forward<OuterA2>(outerAlloc) and inner with innerAllocs... (hence recursively initializing each allocator within the adaptor with the corresponding allocator from the argument list). -?- Remarks: This constructor shall not participate in overload resolution unless is_constructible_v<OuterAlloc, OuterA2> is true. […]
-2- Requires: OuterAlloc shall be constructible from OuterA2.template <class OuterA2> scoped_allocator_adaptor(const scoped_allocator_adaptor<OuterA2, InnerAllocs...>& other) noexcept;-7- Effects: Initializes each allocator within the adaptor with the corresponding allocator from other. -?- Remarks: This constructor shall not participate in overload resolution unless is_constructible_v<OuterAlloc, const OuterA2&> is true.
-6- Requires: OuterAlloc shall be constructible from OuterA2.template <class OuterA2> scoped_allocator_adaptor(scoped_allocator_adaptor<OuterA2, InnerAllocs...>&& other) noexcept;-9- Effects: Initializes each allocator within the adaptor with the corresponding allocator rvalue from other. -?- Remarks: This constructor shall not participate in overload resolution unless is_constructible_v<OuterAlloc, OuterA2> is true.
-8- Requires: OuterAlloc shall be constructible from OuterA2.
Section: 18.8.7 [except.nested] Status: Ready Submitter: Jonathan Wakely Opened: 2016-10-15 Last modified: 2016-11-28
Priority: 0
View all other issues in [except.nested].
View all issues with Ready status.
Discussion:
The discussion notes for LWG 2484 point out there should be an "else, no effects" at the end, which didn't make it into the resolution. Without this it's unclear whether it should do nothing, or be ill-formed, or undefined.
Additionally, the precise effects of the Effects are hard to determine, because the conditions on the static type and dynamic type are intermingled, but must actually be checked separately (the static checks must be done statically and the dynamic checks must be done dynamically!) Furthermore, the obvious way to know if "the dynamic type of e is nested_exception or is publicly and unambiguously derived from nested_exception" is to use dynamic_cast, so we have to use dynamic_cast to find out whether to perform the dynamic_cast expression specified in the Effects. It would make more sense to specify it in terms of a dynamic_cast to a pointer type, and only call rethrow_nested() if the result is not null. The entire spec can be expressed in C++17 as:if constexpr(is_polymorphic_v<E> && (!is_base_of_v<nested_exception, E> || is_convertible_v<E*, nested_exception*>)) if (auto p = dynamic_cast<const nested_exception*>(addressof(e))) p->rethrow_nested();
This uses traits to perform checks on the static type, then uses dynamic_cast to perform the checks on the dynamic type. I think the spec would be clearer if it had the same structure.
[2016-11-12, Issaquah]
Sat AM: Priority 0; move to Ready
Proposed resolution:
This wording is relative to N4606.
Modify 18.8.7 [except.nested] p9:
template <class E> void rethrow_if_nested(const E& e);-9- Effects: If E is not a polymorphic class type, or if nested_exception is an inaccessible or ambiguous base class of E, there is no effect. Otherwise,
if the static type or the dynamic type of e is nested_exception or is publicly and unambiguously derived from nested_exception, callsperforms:dynamic_cast<const nested_exception&>(e).rethrow_nested();if (auto p = dynamic_cast<const nested_exception*>(addressof(e))) p->rethrow_nested();
Section: 27.7.6 [quoted.manip] Status: Ready Submitter: Marshall Clow Opened: 2016-10-27 Last modified: 2016-11-28
Priority: 0
View all other issues in [quoted.manip].
View all issues with Ready status.
Discussion:
Quoted output for strings was added for C++14. But when we merged string_view from the Library Fundamentals TS, we did not add support for quoted output of basic_string_view
[2016-11-12, Issaquah]
Sat AM: Priority 0; move to Ready
13 -> 13 in paragraph modification; and T14 -> T15
Proposed resolution:
This wording is relative to N4606.
Add to the end of the <iomanip> synopsis in [iostream.format.overview]
template <class charT, class traits> T15 quoted(basic_string_view<charT, traits> s, charT delim = charT(’"’), charT escape = charT(’\\’));
Add to [quoted.manip] at the end of p2:
template <class charT, class traits> unspecified quoted(basic_string_view<charT, traits> s, charT delim = charT(’"’), charT escape = charT(’\\’));
Modify [quoted.manip]/3 as follows:
Returns: An object of unspecified type such that if out is an instance of basic_ostream with member type char_type the same as charT and with member type traits_type which in the second and third forms is the same as traits, then the expression out << quoted(s, delim, escape) behaves as a formatted output function (27.7.3.6.1) of out. This forms a character sequence seq, initially consisting of the following elements:
Section: C.4.9 [diff.cpp14.utilities] Status: Ready Submitter: Jonathan Wakely Opened: 2016-10-18 Last modified: 2016-11-28
Priority: 0
View all issues with Ready status.
Discussion:
This is valid in C++11 and C++14:
shared_ptr<int> s{unique_ptr<int[]>{new int[1]}};
The shared_ptr copies the default_delete<int[]> deleter from the unique_ptr, which does the right thing on destruction.
In C++17 it won't compile, because !is_convertible_v<int(*)[], int*>. The solution is to use shared_ptr<int[]>, which doesn't work well in C++14, so there's no transition path. This should be called out in Annex C.[2016-11-12, Issaquah]
Sat AM: Priority 0; move to Ready
Proposed resolution:
This wording is relative to N4606.
Add to C.4.9 [diff.cpp14.utilities]:
20.11.2.2 [util.smartptr.shared]
Change: Different constraint on conversions from unique_ptr. Rationale: Adding array support to shared_ptr, via the syntax shared_ptr<T[]> and shared_ptr<T[N]>. Effect on original feature: Valid code may fail to compile or change meaning in this International Standard. For example:#include <memory> std::unique_ptr<int[]> arr(new int[1]); std::shared_ptr<int> ptr(std::move(arr)); // error: int(*)[] is not compatible with int*
Section: 27.10.11 [class.file_status], 27.10.11.1 [file_status.cons] Status: Ready Submitter: Tim Song Opened: 2016-10-21 Last modified: 2016-11-28
Priority: 0
View all issues with Ready status.
Discussion:
27.10.11 [class.file_status] depicts:
explicit file_status(file_type ft = file_type::none, perms prms = perms::unknown) noexcept;
while 27.10.11.1 [file_status.cons] describes two constructors:
explicit file_status() noexcept; explicit file_status(file_type ft, perms prms = perms::unknown) noexcept;
It's also not clear why the default constructor needs to be explicit. Unlike tag types, there doesn't seem to be a compelling reason to disallow constructing a file_status without naming the type.
[2016-11-12, Issaquah]
Sat AM: Priority 0; move to Ready
Proposed resolution:
This wording is relative to N4606.
Edit 27.10.11 [class.file_status] as indicated:
class file_status { public: // 27.10.11.1, constructors and destructor: file_status() noexcept : file_status(file_type::none) {} explicit file_status(file_type ft= file_type::none, perms prms = perms::unknown) noexcept; […] };
Edit 27.10.11.1 [file_status.cons] as indicated:
explicit file_status() noexcept;
-1- Postconditions: type() == file_type::none and permissions() == perms::unknown.
Section: 23.2.1 [container.requirements.general] Status: Tentatively Ready Submitter: Billy O'Neal III Opened: 2016-11-09 Last modified: 2016-11-28
Priority: Not Prioritized
View other active issues in [container.requirements.general].
View all other issues in [container.requirements.general].
View all issues with Tentatively Ready status.
Discussion:
Addresses US 146
An allocator-aware contiguous container must require an allocator whose pointer type is a contiguous iterator. Otherwise, functions like data for basic_string and vector do not work correctly, along with many other expectations of the contiguous guarantee. Suggested resolution: Add a second sentence to 23.2.1 [container.requirements.general] p13:An allocator-aware contiguous container requires allocator_traits<Allocator>::pointer is a contiguous iterator.
[2016-11-12, Issaquah]
Sat PM: Move to 'Tentatively Ready'
Proposed resolution:
This wording is relative to N4606.
In 17.5.3.5 [allocator.requirements]/5, edit as follows:
-5- An allocator type X shall satisfy the requirements of CopyConstructible (17.6.3.1). The X::pointer, X::const_pointer, X::void_pointer, and X::const_void_pointer types shall satisfy the requirements of NullablePointer (17.6.3.3). No constructor, comparison operator, copy operation, move operation, or swap operation on these pointer types shall exit via an exception. X::pointer and X::const_pointer shall also satisfy the requirements for a random access iterator (
24.2 [iterator.requirements]24.2.7 [random.access.iterators]) and of a contiguous iterator (24.2.1 [iterator.requirements.general]).