Revised 2018-10-08 at 04:58:18 UTC

Tentative Issues


708(i). Locales need to be per thread and updated for POSIX changes

Section: 25 [localization] Status: Tentatively NAD Submitter: Peter Dimov Opened: 2007-07-28 Last modified: 2018-06-24

Priority: Not Prioritized

View all other issues in [localization].

View all issues with Tentatively NAD status.

Discussion:

The POSIX "Extended API Set Part 4,"

http://www.opengroup.org/sib/details.tpl?id=C065

introduces extensions to the C locale mechanism that allow multiple concurrent locales to be used in the same application by introducing a type locale_t that is very similar to std::locale, and a number of _l functions that make use of it.

The global locale (set by setlocale) is now specified to be per- process. If a thread does not call uselocale, the global locale is in effect for that thread. It can install a per-thread locale by using uselocale.

There is also a nice querylocale mechanism by which one can obtain the name (such as "de_DE") for a specific facet, even for combined locales, with no std::locale equivalent.

std::locale should be harmonized with the new POSIX locale_t mechanism and provide equivalents for uselocale and querylocale.

[ Kona (2007): Bill and Nick to provide wording. ]

[ San Francisco: Bill and Nick still intend to provide wording, but this is a part of the task to be addressed by the group that will look into issue 860. ]

[ 2009-07 Frankfurt: ]

It's our intention to stay in sync with WG14. If WG14 makes a decision that requires a change in WG21 the issue will be reopened.

Move to NAD Future.

[LEWG Kona 2017]

Recommend NAD: uselocale() is bad; pass locales around as objects

Proposed resolution:


935(i). clock error handling needs to be specified

Section: 23.17.7 [time.clock] Status: Tentatively NAD Submitter: Beman Dawes Opened: 2008-11-24 Last modified: 2018-06-24

Priority: Not Prioritized

View all issues with Tentatively NAD status.

Discussion:

Each of the three clocks specified in Clocks 23.17.7 [time.clock] provides the member function:

static time_point now();

The semantics specified by Clock requirements 23.17.3 [time.clock.req] make no mention of error handling. Thus the function may throw bad_alloc or an implementation-defined exception (20.5.5.12 [res.on.exception.handling] paragraph 4).

Some implementations of these functions on POSIX, Windows, and presumably on other operating systems, may fail in ways only detectable at runtime. Some failures on Windows are due to supporting chipset errata and can even occur after successful calls to a clock's now() function.

These functions are used in cases where exceptions are not appropriate or where the specifics of the exception or cause of error need to be available to the user. See N2828, Library Support for hybrid error handling (Rev 1), for more specific discussion of use cases. Thus some change in the interface of now is required.

The proposed resolution has been implemented in the Boost version of the chrono library. No problems were encountered.

[ Batavia (2009-05): ]

We recommend this issue be deferred until the next Committee Draft has been issued and the prerequisite paper has been accepted.

Move to Open.

[ 2009-10 Santa Cruz: ]

Mark as NAD future. Too late to make this change without having already accepted the hybrid error handling proposal.

[LEWG Kona 2017]

Recommend NAD. Needs a paper. Proposed resolution no longer applies.

Proposed resolution:

Accept the proposed wording of N2828, Library Support for hybrid error handling (Rev 1).

Change Clock requirements 23.17.3 [time.clock.req] as indicated:

-2- In Table 55 C1 and C2 denote clock types. t1 and t2 are values returned by C1::now() where the call returning t1 happens before (1.10) the call returning t2 and both of these calls happen before C1::time_point::max(). ec denotes an object of type error_code (22.5.3.1 [syserr.errcode.overview]).

Table 55 — Clock requirements
ExpressionReturn typeOperational semantics
... ... ...
C1::now() C1::time_point Returns a time_point object representing the current point in time.
C1::now(ec) C1::time_point Returns a time_point object representing the current point in time.

Change class system_clock 23.17.7.1 [time.clock.system] as indicated:

static time_point now(error_code& ec=throws());

Change class monotonic_clock 99 [time.clock.monotonic] as indicated:

static time_point now(error_code& ec=throws());

Change class high_resolution_clock 23.17.7.7 [time.clock.hires] as indicated:

static time_point now(error_code& ec=throws());

1121(i). Support for multiple arguments

Section: 23.16.4 [ratio.arithmetic] Status: Tentatively NAD Submitter: Alisdair Meredith Opened: 2009-05-25 Last modified: 2018-06-24

Priority: Not Prioritized

View all other issues in [ratio.arithmetic].

View all issues with Tentatively NAD status.

Discussion:

Both add and multiply could sensibly be called with more than two arguments. The variadic template facility makes such declarations simple, and is likely to be frequently wrapped by end users if we do not supply the variant ourselves.

We deliberately ignore divide at this point as it is not transitive. Likewise, subtract places special meaning on the first argument so I do not suggest extending that immediately. Both could be supported with analogous wording to that for add/multiply below.

Note that the proposed resolution is potentially incompatible with that proposed for 921, although the addition of the typedef to ratio would be equally useful.

[ 2009-10-30 Alisdair adds: ]

The consensus of the group when we reviewed this in Santa Cruz was that 921 would proceed to Ready as planned, and the multi-paramater add/multiply templates should be renamed as ratio_sum and ratio_product to avoid the problem mixing template aliases with partial specializations.

It was also suggested to close this issue as NAD Future as it does not correspond directly to any NB comment. NBs are free to submit a specific comment (and re-open) in CD2 though.

Walter Brown also had concerns on better directing the order of evaluation to avoid overflows if we do proceed for 0x rather than TR1, so wording may not be complete yet.

[ Alisdair updates wording. ]

[ 2009-10-30 Howard: ]

Moved to Tentatively NAD Future after 5 positive votes on c++std-lib.

[LEWG Kona 2017]

PR for ratio_product is wrong, uses ratio_add instead of ratio_multiply. Recommend NAD: Doesn't meet the bar for standardization: hasn't been requested again in 7 years, easy to implement yourself.

Rationale:

Does not have sufficient support at this time. May wish to reconsider for a future standard.

Proposed resolution:

Add the following type traits to p3 23.16 [ratio]

// ratio arithmetic
template <class R1, class R2> struct ratio_add;
template <class R1, class R2> struct ratio_subtract;
template <class R1, class R2> struct ratio_multiply;
template <class R1, class R2> struct ratio_divide;
template <class R1, class ... RList> struct ratio_sum;
template <class R1, class ... RList> struct ratio_product;

after 23.16.4 [ratio.arithmetic] p1: add

template <class R1, class ... RList> struct ratio_sum; // declared, never defined

template <class R1> struct ratio_sum<R1> : R1 {};

Requires: R1 is a specialization of class template ratio

template <class R1, class R2, class ... RList> 
 struct ratio_sum<R1, R2, RList...>
   : ratio_add< R1, ratio_sum<R2, RList...>> {
};

Requires: R1 and each element in parmater pack RList is a specialization of class template ratio

after 23.16.4 [ratio.arithmetic] p3: add

template <class R1, class ... RList> struct ratio_product; // declared, never defined

template <class R1> struct ratio_product<R1> : R1 {};

Requires: R1 is a specialization of class template ratio

template <class R1, class R2, class ... RList> 
 struct ratio_sum<R1, R2, RList...>
   : ratio_add< R1, ratio_product<R2, RList...>> {
};

Requires: R1 and each element in parmater pack RList is a specialization of class template ratio


1154(i). complex should accept integral types

Section: 29.5 [complex.numbers] Status: Tentatively NAD Submitter: LWG Opened: 2009-06-28 Last modified: 2018-06-24

Priority: Not Prioritized

View other active issues in [complex.numbers].

View all other issues in [complex.numbers].

View all issues with Tentatively NAD status.

Discussion:

Addresses FR 35

Description

Instantiations of the class template complex<> have to be allowed for integral types, to reflect existing practice and ISO standards (LIA-III).

Suggestion

[ 2009-10-26 Proposed wording in N3002. ]

[ 2010 Pittsburgh: ]

Moved to NAD Future. Rationale added.

[LEWG Kona 2017]

Recommend SG6

[2017-03-03, Kona]

SG6 suggests this issue is a new feature, not a problem with the existing standard, and should therefore be closed NAD. However, SG6 invites papers that bring the proposal up to date with the current standard.

Rationale:

There is no consensus for making this change at this time.

Proposed resolution:

Adopt N3002.


1188(i). Unordered containers should have a minimum load factor as well as a maximum

Section: 26.2.7 [unord.req], 26.5 [unord] Status: Tentatively NAD Submitter: Matt Austern Opened: 2009-08-10 Last modified: 2018-06-21

Priority: Not Prioritized

View other active issues in [unord.req].

View all other issues in [unord.req].

View all issues with Tentatively NAD status.

Discussion:

Unordered associative containers have a notion of a maximum load factor: when the number of elements grows large enough, the containers automatically perform a rehash so that the number of elements per bucket stays below a user-specified bound. This ensures that the hash table's performance characteristics don't change dramatically as the size increases.

For similar reasons, Google has found it useful to specify a minimum load factor: when the number of elements shrinks by a large enough, the containers automatically perform a rehash so that the number of elements per bucket stays above a user-specified bound. This is useful for two reasons. First, it prevents wasting a lot of memory when an unordered associative container grows temporarily. Second, it prevents amortized iteration time from being arbitrarily large; consider the case of a hash table with a billion buckets and only one element. (This was discussed even before TR1 was published; it was TR issue 6.13, which the LWG closed as NAD on the grounds that it was a known design feature. However, the LWG did not consider the approach of a minimum load factor.)

The only interesting question is when shrinking is allowed. In principle the cleanest solution would be shrinking on erase, just as we grow on insert. However, that would be a usability problem; it would break a number of common idioms involving erase. Instead, Google's hash tables only shrink on insert and rehash.

The proposed resolution allows, but does not require, shrinking in rehash, mostly because a postcondition for rehash that involves the minimum load factor would be fairly complicated. (It would probably have to involve a number of special cases and it would probably have to mention yet another parameter, a minimum bucket count.)

The current behavior is equivalent to a minimum load factor of 0. If we specify that 0 is the default, this change will have no impact on backward compatibility.

[ 2010 Rapperswil: ]

This seems to a useful extension, but is too late for 0x. Move to Tentatively NAD Future.

[ Moved to NAD Future at 2010-11 Batavia ]

[LEWG Kona 2017]

Should there be a shrink_to_fit()? Is it too surprising to shrink on insert()? (We understand that shrinking on erase() is not an option.) Maybe make people call rehash(0) to shrink to the min_load_factor? On clear(), the load factor goes to 0 or undefined (0/0), which is likely to violate min_load_factor() min_load_factor(z)'s wording should match max_load_factor(z)'s, e.g. "May change the container’s maximum load factor" Want a paper exploring whether shrink-on-insert has been surprising. From Titus: Google's experience is that maps don't shrink in the way this would help with. NAD, not worth the time. Write a paper if you can demonstrate a need for this.

Proposed resolution:

Add two new rows, and change rehash's postcondition in the unordered associative container requirements table in 26.2.7 [unord.req]:

Table 87 — Unordered associative container requirements (in addition to container)
ExpressionReturn typeAssertion/note pre-/post-condition Complexity
a.min_load_factor() float Returns a non-negative number that the container attempts to keep the load factor greater than or equal to. The container automatically decreases the number of buckets as necessary to keep the load factor above this number. constant
a.min_load_factor(z) void Pre: z shall be non-negative. Changes the container's minimum load factor, using z as a hint. [Footnote: the minimum load factor should be significantly smaller than the maximum. If z is too large, the implementation may reduce it to a more sensible value.] constant
a.rehash(n) void Post: a.bucket_count() >= n, and a.size() <= a.bucket_count() * a.max_load_factor(). [Footnote: It is intentional that the postcondition does not mention the minimum load factor. This member function is primarily intended for cases where the user knows that the container's size will increase soon, in which case the container's load factor will temporarily fall below a.min_load_factor().] a.bucket_cout > a.size() / a.max_load_factor() and a.bucket_count() >= n. Average case linear in a.size(), worst case quadratic.

Add a footnote to 26.2.7 [unord.req] p12:

The insert members shall not affect the validity of references to container elements, but may invalidate all iterators to the container. The erase members shall invalidate only iterators and references to the erased elements.

[A consequence of these requirements is that while insert may change the number of buckets, erase may not. The number of buckets may be reduced on calls to insert or rehash.]

Change paragraph 13:

The insert members shall not affect the validity of iterators if (N+n) < z * B zmin * B <= (N+n) <= zmax * B, where N is the number of elements in the container prior to the insert operation, n is the number of elements inserted, B is the container's bucket count, zmin is the container's minimum load factor, and zmax is the container's maximum load factor.

Add to the unordered_map class synopsis in section 26.5.4 [unord.map], the unordered_multimap class synopsis in 26.5.5 [unord.multimap], the unordered_set class synopsis in 26.5.6 [unord.set], and the unordered_multiset class synopsis in 26.5.7 [unord.multiset]:


float min_load_factor() const;
void min_load_factor(float z);

In 26.5.4.2 [unord.map.cnstr], 26.5.5.2 [unord.multimap.cnstr], 26.5.6.2 [unord.set.cnstr], and 26.5.7.2 [unord.multiset.cnstr], change:

... max_load_factor() returns 1.0 and min_load_factor() returns 0.


1217(i). Quaternion support

Section: 29.5 [complex.numbers] Status: Tentatively NAD Submitter: Ted Shaneyfelt Opened: 2009-09-26 Last modified: 2018-06-24

Priority: Not Prioritized

View other active issues in [complex.numbers].

View all other issues in [complex.numbers].

View all issues with Tentatively NAD status.

Discussion:

Concerning mathematically proper operation of the type:

complex<complex<T> >

Generally accepted mathematical semantics of such a construct correspond to quaternions through Cayly-Dickson construct

(w+xi) + (y+zi) j

The proper implementation seems straightforward by adding a few declarations like those below. I have included operator definition for combining real scalars and complex types, as well, which seems appropriate, as algebra of complex numbers allows mixing complex and real numbers with operators. It also allows for constructs such as complex<double> i=(0,1), x = 12.34 + 5*i;

Quaternions are often used in areas such as computer graphics, where, for example, they avoid the problem of Gimbal lock when rotating objects in 3D space, and can be more efficient than matrix multiplications, although I am applying them to a different field.

/////////////////////////ALLOW OPERATORS TO COMBINE REAL SCALARS AND COMPLEX VALUES /////////////////////////
template<typename T,typename S> complex<T> operator+(const complex<T> x,const S a) {
    complex<T> result(x.real()+a, x.imag());
    return result;
}
template<typename T,typename S> complex<T> operator+(const S a,const complex<T> x) {
    complex<T> result(a+x.real(), x.imag());
    return result;
}
template<typename T,typename S> complex<T> operator-(const complex<T> x,const S a) {
    complex<T> result(x.real()-a, x.imag());
    return result;
}
template<typename T,typename S> complex<T> operator-(const S a,const complex<T> x) {
    complex<T> result(a-x.real(), x.imag());
    return result;
}
template<typename T,typename S> complex<T> operator*(const complex<T> x,const S a) {
    complex<T> result(x.real()*a, x.imag()*a);
    return result;
}
template<typename T,typename S> complex<T> operator*(const S a,const complex<T> x) {
    complex<T> result(a*x.real(), a*x.imag());
    return result;
}

/////////////////////////PROPERLY IMPLEMENT QUATERNION SEMANTICS/////////////////////////
template<typename T> double normSq(const complex<complex<T> >q) {
    return q.real().real()*q.real().real()
         + q.real().imag()*q.real().imag()
         + q.imag().real()*q.imag().real()
         + q.imag().imag()*q.imag().imag();
}
template<typename T> double norm(const complex<complex<T> >q) {
    return sqrt(normSq(q));
}
/////// Cayley-Dickson Construction
template<typename T> complex<complex<T> > conj(const complex<complex<T> > x) {
    complex<complex<T> > result(conj(x.real()),-x.imag());
    return result;
}
template<typename T> complex<complex<T> > operator*(const complex<complex<T> > ab,const complex<complex<T> > cd) {
    complex<T> re(ab.real()*cd.real()-conj(cd.imag())*ab.imag());
    complex<T> im(cd.imag()*ab.real()+ab.imag()*conj(cd.real()));
    complex<complex<double> > q(re,im);
    return q;
}
//// Quaternion division
template<typename S,typename T> complex<complex<T> > operator/(const complex<complex<T> > q,const S a) {
    return q * (1/a);
}
template<typename S,typename T> complex<complex<T> > operator/(const S a,const complex<complex<T> > q) {
    return a*conj(q)/normSq(q);
}
template<typename T> complex<complex<T> > operator/(const complex<complex<T> > n, const complex<complex<T> > d) {
    return n * (conj(d)/normSq(d));
}

[ 2009-10 Santa Cruz: ]

NAD Future. There is no consensus or time to move this into C++0X.

[LEWG Kona 2017]

Recommend SG6 - We note that complex<complex> is the wrong way to spell this

[2017-03-03, Kona]

SG6 suggests this issue is a new feature, not a problem with the existing standard, and should therefore be closed NAD. However, SG6 invites papers that bring the proposal up to date with the current standard.

Proposed resolution:


1235(i). Issue with C++0x random number proposal

Section: 29.7.1.6 [rand.req.dist] Status: Tentatively NAD Submitter: Matthias Troyer Opened: 2009-10-12 Last modified: 2018-06-21

Priority: Not Prioritized

View all other issues in [rand.req.dist].

View all issues with Tentatively NAD status.

Discussion:

There exist optimized, vectorized vendor libraries for the creation of random number generators, such as Intel's MKL [1] and AMD's ACML [2]. In timing tests we have seen a performance gain of a factor of up to 80 (eighty) compared to a pure C++ implementation (in Boost.Random) when using these generator to generate a sequence of normally distributed random numbers. In codes dominated by the generation of random numbers (we have application codes where random number generation is more than 50% of the CPU time) this factor 80 is very significant.

To make use of these vectorized generators, we use a C++ class modeling the RandomNumberEngine concept and forwarding the generation of random numbers to those optimized generators. For example:

namespace mkl {
 class mt19937 {.... };
}

For the generation of random variates we also want to dispatch to optimized vectorized functions in the MKL or ACML libraries. See this example:

mkl::mt19937 eng;
std::normal_distribution<double> dist;

double n = dist(eng);

Since the variate generation is done through the operator() of the distribution there is no customization point to dispatch to Intel's or AMD's optimized functions to generate normally distributed numbers based on the mt19937 generator. Hence, the performance gain of 80 cannot be achieved.

Contrast this with TR1:

mkl::mt19937 eng;
std::tr1::normal_distribution<double> dist;
std::tr1::variate_generator<mkl::mt19937,std::tr1::normal_distribution<double> > rng(eng,dist);
double n = rng();

This - admittedly much uglier from an aestethic point of view - design allowed optimization by specializing the variate_generator template for mkl::mt19937:

namespace std { namespace tr1 {

template<>
class variate_generator<mkl::mt19937,std::tr1::normal_distribution<double> > { .... };

} }

A similar customization point is missing in the C++0x design and prevents the optimized vectorized version to be used.

Suggested resolution:

Add a customization point to the distribution concept. Instead of the variate_generator template this can be done through a call to a free function generate_variate found by ADL instead of operator() of the distribution:

template <RandomNumberDistribution, class RandomNumberEngine>
typename RandomNumberDistribution ::result_type
generate_variate(RandomNumberDistribution const& dist, RandomNumberEngine& eng);

This function can be overloaded for optimized enginges like mkl::mt19937.

[ 2009-10 Santa Cruz: ]

NAD Future. No time to add this feature for C++0X.

[LEWG Kona 2017]

Recommend NAD: The standard has changed enough that the issue doesn't make sense anymore. Write a paper proposing a way to get this performance as changes to the current library.

Proposed resolution:


1282(i). A proposal to add std::split algorithm

Section: 28 [algorithms] Status: Tentatively NAD Submitter: Igor Semenov Opened: 2009-12-07 Last modified: 2018-06-24

Priority: Not Prioritized

View other active issues in [algorithms].

View all other issues in [algorithms].

View all issues with Tentatively NAD status.

Discussion:

  1. Motivation and Scope

    Splitting strings into parts by some set of delimiters is an often task, but there is no simple and generalized solution in C++ Standard. Usually C++ developers use std::basic_stringstream<> to split string into parts, but there are several inconvenient restrictions:

  2. Impact on the Standard

    This algorithm doesn't interfere with any of current standard algorithms.

  3. Design Decisions

    This algorithm is implemented in terms of input/output iterators. Also, there is one additional wrapper for const CharType * specified delimiters.

  4. Example implementation

    template< class It, class DelimIt, class OutIt >
    void split( It begin, It end, DelimIt d_begin, DelimIt d_end, OutIt out )
    {
       while ( begin != end )
       {
           It it = std::find_first_of( begin, end, d_begin, d_end );
           *out++ = std::make_pair( begin, it );
           begin = std::find_first_of( it, end, d_begin, d_end,
               std::not2( std::equal_to< typename It::value_type >() ) );
       }
    }
    
    template< class It, class CharType, class OutIt >
    void split( It begin, It end, const CharType * delim, OutIt out )
    {
       split( begin, end, delim, delim + std::strlen( delim ), out );
    }
    
  5. Usage

    std::string ss( "word1 word2 word3" );
    std::vector< std::pair< std::string::const_iterator, std::string::const_iterator > > v;
    split( ss.begin(), ss.end(), " ", std::back_inserter( v ) );
    
    for ( int i = 0; i < v.size(); ++i )
    {
       std::cout << std::string( v[ i ].first, v[ i ].second ) << std::endl;
    }
    // word1
    // word2
    // word3
    

[ 2010-01-22 Moved to Tentatively NAD Future after 5 positive votes on c++std-lib. Rationale added below. ]

[LEWG Kona 2017]

Recommend NAD: Paper encouraged. Have papers for this; LEWG259.

Rationale:

The LWG is not considering completely new features for standardization at this time. We would like to revisit this good suggestion for a future TR and/or standard.

Proposed resolution:

Add to the synopsis in 28.1 [algorithms.general]:

template< class ForwardIterator1, class ForwardIterator2, class OutputIterator >
  void split( ForwardIterator1 first, ForwardIterator1 last,
              ForwardIterator2 delimiter_first, ForwardIterator2 delimiter_last,
              OutputIterator result );

template< class ForwardIterator1, class CharType, class OutputIterator >
  void split( ForwardIterator1 first, ForwardIterator1 last,
              const CharType * delimiters, OutputIterator result );

Add a new section [alg.split]:

template< class ForwardIterator1, class ForwardIterator2, class OutputIterator >
  void split( ForwardIterator1 first, ForwardIterator1 last,
              ForwardIterator2 delimiter_first, ForwardIterator2 delimiter_last,
              OutputIterator result );

1. Effects: splits the range [first, last) into parts, using any element of [delimiter_first, delimiter_last) as a delimiter. Results are pushed to output iterator in the form of std::pair<ForwardIterator1, ForwardIterator1>. Each of these pairs specifies a maximal subrange of [first, last) which does not contain a delimiter.

2. Returns: nothing.

3. Complexity: Exactly last - first assignments.

template< class ForwardIterator1, class CharType, class OutputIterator >
  void split( ForwardIterator1 first, ForwardIterator1 last,
              const CharType * delimiters, OutputIterator result );

1. Effects: split the range [first, last) into parts, using any element of delimiters (interpreted as zero-terminated string) as a delimiter. Results are pushed to output iterator in the form of std::pair<ForwardIterator1, ForwardIterator1>. Each of these pairs specifies a maximal subrange of [first, last) which does not contain a delimiter.

2. Returns: nothing.

3. Complexity: Exactly last - first assignments.


1289(i). Generic casting requirements for smart pointers

Section: 23.2 [utility] Status: Tentatively NAD Submitter: Ion Gaztañaga Opened: 2009-12-14 Last modified: 2018-06-21

Priority: Not Prioritized

View all other issues in [utility].

View all issues with Tentatively NAD status.

Discussion:

In section 20.5.3.5 [allocator.requirements], Table 40 — Allocator requirements, the following expression is required for allocator pointers:

Table 40 — Allocator requirements
Expression Return type Assertion/note
pre-/post-condition
Default
static_cast<X::pointer>(w) X::pointer static_cast<X::pointer>(w) == p  

To achieve this expression, a smart pointer writer must introduce an explicit conversion operator from smart_ptr<void> to smart_ptr<T> so that static_cast<pointer>(void_ptr) is a valid expression. Unfortunately this explicit conversion weakens the safety of a smart pointer since the following expression (invalid for raw pointers) would become valid:

smart_ptr<void> smart_v = ...;
smart_ptr<T> smart_t(smart_v);

On the other hand, shared_ptr also defines its own casting functions in 23.11.3.9 [util.smartptr.shared.cast], and although it's unlikely that a programmer will use shared_ptr as allocator::pointer, having two different ways to do the same cast operation does not seem reasonable. A possible solution would be to replace static_cast<X::pointer>(w) expression with a user customizable (via ADL) static_pointer_cast<value_type>(w), and establish the xxx_pointer_cast functions introduced by shared_ptr as the recommended generic casting utilities of the standard.

Unfortunately, we've experienced problems in Boost when trying to establish xxx_pointer_cast as customization points for generic libraries (http://objectmix.com/c/40424-adl-lookup-explicit-template-parameters.html) because these casting functions are called with explicit template parameters and the standard says in 17.9.1 [temp.arg.explicit] p.8 "Explicit template argument specification":

8 ...But when a function template with explicit template arguments is used, the call does not have the correct syntactic form unless there is a function template with that name visible at the point of the call. If no such name is visible, the call is not syntactically well-formed and argument-dependent lookup does not apply.

So we can do this:

template<class BasePtr>
void generic_ptr_swap(BasePtr p)
{
  //ADL customization point
  swap(p, p);
  //...
}

but not the following:

template<class BasePtr>
void generic_ptr_algo(BasePtr p)
{
  typedef std::pointer_traits<BasePtr>::template
     rebind<Derived> DerivedPtr;
  DerivedPtr dp = static_pointer_cast<Derived>(p);
}

The solution to make static_pointer_cast a customization point is to add a generic declaration (no definition) of static_pointer_cast in a namespace (like std) and apply "using std::static_pointer_cast" declaration to activate ADL:

namespace std{

template<typename U, typename T>
unspecified
static_pointer_cast(T&&) = delete;

}

template<class BasePtr>
void generic_ptr_algo(BasePtr p)
{
  typedef std::pointer_traits<BasePtr>::template
     rebind<Derived> DerivedPtr;

  //ADL applies because static_pointer_cast is made
  //  visible according to [temp.arg.explicit]/8
  using std::static_pointer_cast;

  DerivedPtr dp = static_pointer_cast<Derived>(p);

  //...
}

A complete solution will need also the definition of static_pointer_cast for raw pointers, and this definition has been present in Boost (http://www.boost.org/boost/ pointer_cast.hpp) for years.

[ 2010-03-26 Daniel made editorial adjustments to the proposed wording. ]

[ Moved to NAD Future at 2010-11 Batavia ]

This is a new feature rather than a defect. It can be added later: "this is such a hairy area that people will put up with changes"

[LEWG Kona 2017]

Recommend NAD: NAD. Should bring a paper as a proposal for 2020.

Proposed resolution:

Add to section 23.2 [utility] Utility components, Header <utility> synopsis:

// 20.3.X, generic pointer cast functions

template<typename U, typename T>
unspecified
static_pointer_cast(T&&) = delete;

template<typename U, typename T>
unspecified
dynamic_pointer_cast(T&&) = delete;

template<typename U, typename T>
unspecified
const_pointer_cast(T&&) = delete;

//Overloads for raw pointers
template<typename U, typename T>
auto static_pointer_cast(T* t) -> decltype(static_cast<U*>(t));

template<typename U, typename T>
auto dynamic_pointer_cast(T* t) -> decltype(dynamic_cast<U*>(t));

template<typename U, typename T>
auto const_pointer_cast(T* t) -> decltype(const_cast<U*>(t));

Add to section 23.2 [utility] Utility components, a new subclause 20.3.X Pointer cast utilities [pointer.cast]:

20.3.X Pointer cast utilities [pointer.cast]

1 The library defines generic pointer casting function templates so that template code can explicitly make these names visible and activate argument-dependent lookup for pointer cast calls.

//Generic declarations
template<typename U, typename T>
unspecified
static_pointer_cast(T&&) = delete;

template<typename U, typename T>
unspecified
dynamic_pointer_cast(T&&) = delete;

template<typename U, typename T>
unspecified
const_pointer_cast(T&&) = delete;

2 The library also defines overloads of these functions for raw pointers.

//Overloads for raw pointers
template<typename U, typename T>
auto static_pointer_cast(T* t) -> decltype(static_cast<U*>(t));

Returns: static_cast<U*>(t)

template<typename U, typename T>
auto dynamic_pointer_cast(T* t) -> decltype(dynamic_cast<U*>(t));

Returns: dynamic_cast<U*>(t)

template<typename U, typename T>
auto const_pointer_cast(T* t) -> decltype(const_cast<U*>(t));

Returns: const_cast<U*>(t)

[Example:

#include <utility> //static_pointer_cast
#include <memory>  //pointer_traits

class Base{};
class Derived : public Base{};

template<class BasePtr>
void generic_pointer_code(BasePtr b)
{
   typedef std::pointer_traits<BasePtr>::template
      rebind<Derived> DerivedPtr;

   using std::static_pointer_cast;
   //ADL applies now that static_pointer_cast is visible
   DerivedPtr d = static_pointer_cast<Derived>(b);
}

end example]

Replace in section 20.5.3.5 [allocator.requirements] Table 40 — Allocator requirements, the following table entries for allocator pointers:

Table 40 — Allocator requirements
Expression Return type Assertion/note
pre-/post-condition
Default
static_pointer_cast<X::pointerT>(w) X::pointer static_pointer_cast<X::pointerT>(w) == p  
static_pointer_cast<X::const_pointerconst T>(w) X::const_pointer static_pointer_cast<X::const_pointerconst T>(z) == q  

1317(i). make_hash

Section: 23.14.15 [unord.hash] Status: Tentatively NAD Submitter: Nicolai M. Josuttis Opened: 2010-02-10 Last modified: 2018-06-24

Priority: Not Prioritized

View other active issues in [unord.hash].

View all other issues in [unord.hash].

View all issues with Tentatively NAD status.

Discussion:

Currently, the library lacks a convenient way to provide a hash function that can be used with the provided unordered containers to allow the usage of non trivial element types.

While we can easily declare an

std::unordered_set<int>

or

std::unordered_set<std::string>

we have no easy way to declare an unordered_set for a user defined type. IMO, this is a big obstacle to use unordered containers in practice. Note that in Java, the wide usage of HashMap is based on the fact that there is always a default hash function provided.

Of course, a default hash function implies the risk to provide poor hash functions. But often even poor hash functions are good enough.

While I really would like to see a default hash function, I don't propose it here because this would probably introduce a discussion that's too big for this state of C++0x.

However, I strongly suggest at least to provide a convenience variadic template function make_hash<>() to allow an easy definition of a (possibly poor) hash function.

As a consequence for a user-defined type such as

class Customer {
   friend class CustomerHash;
   private:
     string firstname;
     string lastname;
     long   no;
   ...
 };

would allow to specify:

class CustomerHash : public std::unary_function<Customer, std::size_t>
{
  public:
    std::size_t operator() (const Customer& c) const  {
       return make_hash(c.firstname,c.lastname,c.no);
    }
};

instead of:

class CustomerHash : public std::unary_function<Customer, std::size_t>
{
  public:
    std::size_t operator() (const Customer& c) const  {
       return std::hash<std::string>()(c.firstname) +
              std::hash<std::string>()(c.lastname) +
              std::hash<long>()(c.no);
    }
};

Note that, in principle, we can either specify that

make_hash returns the sum of a call of std::hash<T>()(x) for each argument x of type T

or we can specify that

make_hash provides a hash value for each argument, for which a std::hash() function is provided

with the possible note that the hash value may be poor or only a good hash value if the ranges of all passed arguments is equally distributed.

For my convenience, I propose wording that describes the concrete implementation.

[ 2010 Pittsburgh: Moved to NAD Editorial, rationale added below. ]

[LEWG Kona 2017]

Recommend NAD: Feature? Needs a paper. (This is LEWG21)

Rationale:

There is no consensus to make this change at this time.

Proposed resolution:

In Function objects 23.14 [function.objects] in paragraph 2 at the end of the Header <functional> synopsis insert:

// convenience functions
template <class T>
  size_t make_hash (const T&);
template <class T, class... Types>
  size_t make_hash (const T&, const Types&...);

In Class template hash 23.14.15 [unord.hash] add:

20.7.16.1 Hash creation functions [hash.creation]

template <class T>
  size_t make_hash (const T& val);

Returns: hash<T>()(val);

template <class T, class... Types>
  size_t make_hash (const T& val, const Types&... args);

Returns: hash<T>()(val) + std::make_hash(args...)


1406(i). Support hashing smart-pointers based on owner

Section: 23.11.3 [util.smartptr.shared] Status: Tentatively NAD Submitter: Japan Opened: 2010-08-25 Last modified: 2018-06-21

Priority: Not Prioritized

View other active issues in [util.smartptr.shared].

View all other issues in [util.smartptr.shared].

View all issues with Tentatively NAD status.

Discussion:

Addresses JP-5

Hash support based on ownership sharing should be supplied for shared_ptr and weak_ptr. For two shared_ptr objects p and q, two distinct equivalence relations can be defined. One is based on equivalence of pointer values, which is derived from the expression p.get() == q.get() (hereafter called address based equivalence relation), the other is based on equivalence of ownership sharing, which is derived from the expression !p.owner_before(q) && !q.owner_before(p) (hereafter called ownership-based equivalence relation). These two equivalence relations are independent in general. For example, a shared_ptr object created by the constructor of the signature shared_ptr(shared_ptr<U> const &, T *) could reveal a difference between these two relations. Therefore, hash support based on each equivalence relation should be supplied for shared_ptr. However, while the standard library provides the hash support for address-based one (20.9.11.6 paragraph 2), it lacks the hash support for ownership-based one. In addition, associative containers work well in combination with the shared_ptr's ownership-based comparison but unordered associative containers don't. This is inconsistent.

For the case of weak_ptr, hash support for the ownership based equivalence relation can be safely defined on weak_ptrs, and even on expired ones. The absence of hash support for the ownership-based equivalence relation is fatal, especially for expired weak_ptrs. And the absence of such hash support precludes some quite effective use-cases, e.g. erasing the unordered_map entry of an expired weak_ptr key from a customized deleter supplied to shared_ptrs.

Hash support for the ownership-based equivalence relation cannot be provided by any user-defined manner because information about ownership sharing is not available to users at all. Therefore, the only way to provide ownership-based hash support is to offer it intrusively by the standard library.

As far as we know, such hash support is implementable. Typical implementation of such hash function could return the hash value of the pointer of the counter object that is internally managed by shared_ptr and weak_ptr.

[2010 Rapperswil:]

No consensus to make this change at this time.

[LEWG Kona 2017]

Recommend NAD: Needs a paper. Feature. Exposing an implementation detail (indirectly observable via hash).

Proposed resolution:

Add the following non-static member functions to shared_ptr and weak_ptr class template;

Update [util.smartptr.shared], 20.9.11.2 paragraph 1

namespace std{
template<class T> class shared_ptr {
public:
...
  size_t owner_hash() const;
...
};
}

Update [util.smartptr.weak], 20.9.11.3 paragraph 1

namespace std{
template<class T> class weak_ptr {
public:
...
  size_t owner_hash() const;
...
};
}

These functions satisfy the following requirements. Let p and q be objects of either shared_ptr or weak_ptr, H be a hypothetical function object type that satisfies the hash requirements ([hash.requirements], 20.2.4) and h be an object of the type H. The expression p.owner_hash() behaves as if it were equivalent to the expression h(p). In addition, h(p) == h(q) must become true if p and q share ownership.


1499(i). Condition variables preclude wakeup optimization

Section: 33.5 [thread.condition] Status: Tentatively NAD Submitter: INCITS Opened: 2010-08-25 Last modified: 2018-06-21

Priority: Not Prioritized

View all other issues in [thread.condition].

View all issues with Tentatively NAD status.

Discussion:

Addresses US-193

Condition variables preclude a wakeup optimization.

[ Resolution proposed by ballot comment: ]

Change condition_variable to allow such optimization. See Appendix 1 - Additional Details

[ 2010 Batavia ]

The Concurrency subgroup reviewed the issue, and deemed it an extension to be handled after C++0x.

Rationale:

The LWG does not wish to make the change at this time.

[LEWG Kona 2017]

Recommend NAD: (N4618 numbering) 30.5.1[thread.condition.condvar] p10.3 allows spurious wakeups. This issue is out of date.

[2017-03-01, Kona]

SG1 recommends: Close as NAD

The approach suggested there raises all sorts of issues about thread_locals, etc. It's probably way too late to change this anyway, but this would have required a careful paper.

Proposed resolution:


2226(i). wstring_convert methods do not take allocator instance

Section: D.14.1 [depr.conversions.string] Status: Tentatively NAD Submitter: Glen Fernandes Opened: 2012-12-14 Last modified: 2018-06-24

Priority: Not Prioritized

View other active issues in [depr.conversions.string].

View all other issues in [depr.conversions.string].

View all issues with Tentatively NAD status.

Discussion:

The wstring_convert class template, described in D.14.1 [depr.conversions.string], does not support custom stateful allocators. It only supports custom stateless allocators.

The to_bytes member function returns basic_string<char, char_traits<char>, Byte_alloc> but it does not take an instance of Byte_alloc to pass to the constructor of the basic_string.

Similarly the from_bytes member function returns basic_string<Elem, char_traits<Elem>, Wide_alloc> but it does not take an instance of Wide_alloc to pass to the constructor of the basic_string.

This makes these two member functions and the wstring_convert class template not usable when Wide_alloc or Byte_alloc are stateful allocators.

[2013-01-22, Glen provides wording]

[2013-03-15 Issues Teleconference]

Moved to NAD Future.

This is clearly an extension that the LEWG may want to take a look at, once we have more experience with appropriate use of allocators with the C++11 model.

[LEWG Kona 2017]

Recommend NAD: Does this follow the pattern? Should be discussed as a group. Do we have the experience with the C++11 allocator model to know that this is the addition to make?

Should to_string() also take an allocator? substr()? Any function that returns a string?

This suggests a larger change.

Proposed resolution:

This wording is relative to N3485.

  1. In D.14.1 [depr.conversions.string]/2 and /6 "Class template wstring_convert synopsis" change the overloads of the member function from_bytes() so that all four overloads take an additional parameter which is an instance of Wide_alloc:

    wide_string from_bytes(char byte, const Wide_alloc& alloc = Wide_alloc());
    wide_string from_bytes(const char *ptr, const Wide_alloc& alloc = Wide_alloc());
    wide_string from_bytes(const byte_string& str, const Wide_alloc& alloc = Wide_alloc());
    wide_string from_bytes(const char *first, const char *last, const Wide_alloc& alloc = Wide_alloc());
    
  2. In D.14.1 [depr.conversions.string] /8 specify that this Wide_alloc allocator parameter is used to construct the wide_string object returned from the function:

    -7- Effects: The first member function shall convert the single-element sequence byte to a wide string. The second member function shall convert the null-terminated sequence beginning at ptr to a wide string. The third member function shall convert the sequence stored in str to a wide string. The fourth member function shall convert the sequence defined by the range [first, last) to a wide string.

    -8- In all cases:

  3. In D.14.1 [depr.conversions.string]/2 and /12 "Class template wstring_convert synopsis" change the overloads of the member function to_bytes() so that all four overloads take an additional parameter which is an instance of Byte_alloc:

    byte_string to_bytes(Elem wchar, const Byte_alloc& alloc = Byte_alloc());
    byte_string to_bytes(const Elem *wptr, const Byte_alloc& alloc = Byte_alloc());
    byte_string to_bytes(const wide_string& wstr, const Byte_alloc& alloc = Byte_alloc());
    byte_string to_bytes(const Elem *first, const Elem *last, const Byte_alloc& alloc = Byte_alloc());
    
  4. In D.14.1 [depr.conversions.string] /13 specify that this Byte_alloc allocator parameter is used to construct the byte_string object returned from the function:

    -12- Effects: The first member function shall convert the single-element sequence wchar to a byte string. The second member function shall convert the null-terminated sequence beginning at wptr to a byte string. The third member function shall convert the sequence stored in wstr to a byte string. The fourth member function shall convert the sequence defined by the range [first, last) to a byte string.

    -13- In all cases:


2417(i). [fund.ts.v2] std::experimental::optional::operator< and LessThanComparable requirement

Section: 5.7 [fund.ts.v2::optional.relops], 5.9 [fund.ts.v2::optional.comp_with_t] Status: Tentatively NAD Submitter: Daniel Krügler Opened: 2014-06-20 Last modified: 2018-06-24

Priority: Not Prioritized

View all issues with Tentatively NAD status.

Discussion:

Addresses: fund.ts.v2

Currently, std::experimental::optional::operator== imposes the EqualityComparable requirement which provides two guarantees: It ensures that operator!= can rely on the equivalence-relation property and more importantly, that the BooleanTestable requirements suggested by issue 2114 are automatically implied.

std::experimental::optional::operator< doesn't provide a LessThanComparable requirement, but there was quite an historic set of changes involved with that family of types: As of N3527 this operator was defined in terms of operator< of the contained type T and imposed the LessThanComparable requirement. In the final acceptance step of optional by the committee, the definition was expressed in terms of std::less and the LessThanComparable requirement had been removed.

The inconsistency between operator== and operator< should be removed. One possible course of action would be to add the LessThanComparable to std::experimental::optional::operator<. The EqualityComparable requirement of operator== could also be removed, but in that case both operators would at least need to require the BooleanTestable requirements (see 2114) for the result type of T's operator== and operator<.

Arguably, corresponding operators for pair and tuple do not impose LessThanComparable (nor EqualityComparable), albeit the definition of the "derived" relation functions depend on properties ensured by LessThanComparable. According to the SGI definition, the intention was to imposed both EqualityComparable and LessThanComparable. If this is not intended, the standard should clarify this position.

[2015-02 Cologne]

VV, DK, JY discuss why and when LessThanComparable was removed. AM: Move to LEWG. Please tell LWG when you look at it.

[2016-11-08, Issaquah]

Not adopted during NB comment resolution

[LEWG Kona 2017]

Recommend NAD: We've done a lot of work getting the C++17 semantics we want in this area; we're not going to change them 3 days from DIS or change the TSv2 behavior to be different from '17.

Proposed resolution:


2600(i). ios_base must store inaccessible iostate flags

Section: 30.5.3.5 [ios.base.storage] Status: Tentatively NAD Submitter: David Krauss Opened: 2016-03-14 Last modified: 2018-06-21

Priority: Not Prioritized

View all other issues in [ios.base.storage].

View all issues with Tentatively NAD status.

Discussion:

DR 41, "Ios_base needs clear(), exceptions()" stopped short of providing the interface suggested in its title, but it did require the underlying state to be stored in ios_base. Because rdstate() is also missing, ios_base manipulators relying on iword and pword cannot detect failure. The only safe alternative is to manipulate a derived class, which must be a template.

libc++ already provides the interface as a nonconforming extension. libstdc++ implements the internal state but leaves it frustratingly inaccessible, as specified. Any conforming implementation should be able to provide the interface without ABI problems.

[2016-04, Issues Telecon]

This is really a request for an (feature) API. Passing to LEWG.

[LEWG Kona 2017]

Recommend NAD: iostreams aren't used in this way enough to spend committee time on it. However, a paper could change our minds.

Proposed resolution:


2943(i). Problematic specification of the wide version of basic_filebuf::open

Section: 30.9.2.3 [filebuf.members] Status: Tentatively Ready Submitter: Tim Song Opened: 2017-03-09 Last modified: 2018-08-27

Priority: 2

View all other issues in [filebuf.members].

View all issues with Tentatively Ready status.

Discussion:

LWG 2676 specified basic_filebuf::open(const std::filesystem::path::value_type* s, ios_base::openmode mode) by simply reusing the specification for the const char* overload, but that specification is incorrect for the wide overload: it says that s is an NTBS — a null-terminated byte string — which it isn't. Moreover, it specifies that the file is opened as if by calling fopen(s, modstr), but that call is ill-formed if s isn't a const char*.

[2017-07 Toronto Wed Issue Prioritization]

Priority 2

[2017-11 Albuquerque Wednesday issue processing]

Status to Open; Jonathan to provide wording.

[2018-01-16; Jonathan and Tim Song provide wording]

We'll have to ask the Microsoft guys if "as by a call to fopen" is OK for them. There are paths that can be represented as a wide character string that can't reliably be converted to narrow characters (because they become dependent on the current codepage, or some other Windows nonsense) so they definitely won't use fopen. But as long as they call something that behaves like it (which should allow _fwopen), I think they'll still meet the spirit of the wording.

[2018-08-14; Marshall corrects a grammar nit in the P/R]

The Microsoft guys note that "as by a call to fopen" is OK by them.

Previous resolution [SUPERSEDED]:

This wording is relative to N4713.

  1. Edit 30.9.2.3 [filebuf.members] as indicated:

    basic_filebuf* open(const char* s, ios_base::openmode mode);
    basic_filebuf* open(const filesystem::path::value_type* s,
                        ios_base::openmode mode); // wide systems only; see 30.9.1 [fstream.syn]
    

    -?- Requires: s shall point to a NTCTS (20.3.16 [defns.ntcts]).

    -2- Effects: If is_open() != false, returns a null pointer. Otherwise, initializes the filebuf as required. It then opens the file to which s resolves, if possible, as if by a call to fopen with the second argumenta file, if possible, whose name is the ntbs s (as if by calling fopen(s, modstr)). The ntbs modstr is determined from mode & ~ios_base::ate as indicated in Table 117. If mode is not some combination of flags shown in the table then the open fails.

    -3- If the open operation succeeds and (mode & ios_base::ate) != 0, positions the file to the end (as if by calling fseek(file, 0, SEEK_END), where file is the pointer returned by calling fopen).(footnote 330)

    -4- If the repositioning operation fails, calls close() and returns a null pointer to indicate failure.

    -5- Returns: this if successful, a null pointer otherwise.

[2018-08-23 Batavia Issues processing]

Adopted after changing 'Requires' -> 'Expects' in the P/R.

Proposed resolution:

This wording is relative to N4713.

  1. Edit 30.9.2.3 [filebuf.members] as indicated:

    basic_filebuf* open(const char* s, ios_base::openmode mode);
    basic_filebuf* open(const filesystem::path::value_type* s,
                        ios_base::openmode mode); // wide systems only; see 30.9.1 [fstream.syn]
    

    -?- Expects: s shall point to a NTCTS (20.3.16 [defns.ntcts]).

    -2- Effects: If is_open() != false, returns a null pointer. Otherwise, initializes the filebuf as required. It then opens the file to which s resolves, if possible, as if by a call to fopen with the second argumenta file, if possible, whose name is the ntbs s (as if by calling fopen(s, modstr)). The ntbs modstr is determined from mode & ~ios_base::ate as indicated in Table 117. If mode is not some combination of flags shown in the table then the open fails.

    -3- If the open operation succeeds and (mode & ios_base::ate) != 0, positions the file to the end (as if by calling fseek(file, 0, SEEK_END), where file is the pointer returned by calling fopen).(footnote 330)

    -4- If the repositioning operation fails, calls close() and returns a null pointer to indicate failure.

    -5- Returns: this if successful, a null pointer otherwise.


2960(i). [fund.ts.v3] nonesuch is insufficiently useless

Section: 3.3 [fund.ts.v3::meta] Status: Tentatively Ready Submitter: Tim Song Opened: 2017-05-08 Last modified: 2018-08-27

Priority: 2

View all issues with Tentatively Ready status.

Discussion:

Addresses: fund.ts.v3

The definition of std::experimental::nonesuch (with a deleted default constructor, destructor, copy constructor, and copy assignment operator) means that it is an aggregate, which means that it can be initialized from {} in contexts where the availability of the destructor is not considered (e.g., overload resolution or a new-expression).

The deleted default constructor also has this effect standing alone, because it doesn't affect the formation of implicit conversion sequences (and hence overload resolution). The net result is ambiguities in situations like:

struct such {};
void f(const such&);
void f(const nonesuch&);
f({});

For a real-life example of such ambiguity, see GCC bug 79141, involving libstdc++'s internal __nonesuch type defined just like the one in the fundamentals TS.

I believe that nonesuch would be substantially more useful if the ICS from {} is gone. nonesuch should have no default constructor (rather than a deleted one), and it shouldn't be an aggregate.

[2017-11-20 Priority set to 2 after discussion on the reflector.]

Previous resolution [SUPERSEDED]:

This wording is relative to N4617.

  1. Edit 3.3.1 [fund.ts.v3::meta.type.synop] as indicated, moving the definition of nonesuch to 3.3.3 [fund.ts.v3::meta.detect]:

    //3.3.3 [fund.ts.v3::meta.detect], Detection idiom
    […]
    
    struct nonesuch{
      nonesuch() = delete;
      ~nonesuch() = delete;
      nonesuch(nonesuch const&) = delete;
      void operator=(nonesuch const&) = delete;
    };
    […]
    

  2. Insert at the beginning of 3.3.3 [fund.ts.v3::meta.detect] the following paragraphs:

    [Drafting note: The seemingly redundant statement about default and initializer-list constructors is intended to negate the usual leeway for implementations to declare additional member function signatures granted in 20.5.5.5 [member.functions]. — end drafting note]

    struct nonesuch {
      ~nonesuch() = delete;
      nonesuch(nonesuch const&) = delete;
      void operator=(nonesuch const&) = delete;
    };
    

    -?- nonesuch has no default constructor (C++14 §[class.ctor]) or initializer-list constructor (C++14 §[dcl.init.list]), and is not an aggregate (C++14 §[dcl.init.aggr]).

[2018-08-23 Batavia Issues processing]

Change C++14 references to C++17, and all the LFTS2 references to LFTS3

Status to Tentatively Ready

Proposed resolution:

This wording is relative to N4617.

  1. Edit 3.3.1 [fund.ts.v3::meta.type.synop] as indicated, moving the definition of nonesuch to 3.3.3 [fund.ts.v3::meta.detect]:

    //3.3.3 [fund.ts.v3::meta.detect], Detection idiom
    […]
    
    struct nonesuch{
      nonesuch() = delete;
      ~nonesuch() = delete;
      nonesuch(nonesuch const&) = delete;
      void operator=(nonesuch const&) = delete;
    };
    […]
    

  2. Insert at the beginning of 3.3.3 [fund.ts.v3::meta.detect] the following paragraphs:

    [Drafting note: The seemingly redundant statement about default and initializer-list constructors is intended to negate the usual leeway for implementations to declare additional member function signatures granted in 20.5.5.5 [member.functions]. — end drafting note]

    struct nonesuch {
      ~nonesuch() = delete;
      nonesuch(nonesuch const&) = delete;
      void operator=(nonesuch const&) = delete;
    };
    

    -?- nonesuch has no default constructor (C++17 §[class.ctor]) or initializer-list constructor (C++17 §[dcl.init.list]), and is not an aggregate (C++17 §[dcl.init.aggr]).


3008(i). make_shared (sub)object destruction semantics are not specified

Section: 23.11.3.6 [util.smartptr.shared.create] Status: Tentatively Ready Submitter: Glen Joseph Fernandes Opened: 2017-08-06 Last modified: 2018-08-27

Priority: 2

View all other issues in [util.smartptr.shared.create].

View all issues with Tentatively Ready status.

Discussion:

The remarks for the make_shared and allocate_shared functions do not specify how the objects managed by the returned shared_ptr are destroyed. It is implied that when objects are constructed via a placement new expression, they are destroyed by calling the destructor, and that when objects are constructed via an allocator, they are destroyed using that allocator. This should be explicitly specified.

[2017-11 Albuquerque Wednesday night issues processing]

Priority set to 2

Previous resolution [SUPERSEDED]:

This resolution is relative to N4687.

  1. Edit 23.11.3.6 [util.smartptr.shared.create] as indicated:

    template<class T, ...>
    shared_ptr<T> make_shared(args);
    template<class T, class A, ...>
    shared_ptr<T> allocate_shared(const A& a, args);
    

    […]

    -7- Remarks:

    1. […]

    2. (7.9) — When the lifetime of the object managed by the return value ends, or when the initialization of an array element throws an exception, the initialized elements should be destroyed in the reverse order of their construction.

    3. (7.?) — When a (sub)object of a non-array type U that was initialized by make_shared is to be destroyed, it shall be destroyed via the expression pv->~U() where pv points to that object of type U.

    4. (7.?) — When a (sub)object of a non-array type U that was initialized by allocate_shared is to be destroyed, it shall be destroyed via the expression allocator_traits<A2>::destroy(a2, pv) where pv points to that object of type cv-unqualified U and a2 of type A2 is a rebound copy of the allocator a passed to allocate_shared such that its value_type is remove_cv_t<U>.

[2018-06 Rapperswil Wednesday night issues processing]

CC: what is "of type cv-unqualified U" and "remove_cv_T<U>" about?
DK: again, it isn't new wording; it is in p 7.5.2
JW: but none of the words use "of type cv-unqualified U"
CT: so we should also used remove_cv_T<U> instead?
JW: I would like to talk to Glen
FB: does anybody know how it works for an array of arrays? It seems to cover the case
JW: we could leave it vague as it is now or specify it to exactly what it does
DK: I think we should split the thing into two parts and start with definitions
DK: ACTION I can refactor the wording
MC: there was a fairly long message thread when we talked about this

Daniel comments and improves wording:

The currently allocator requirements support only the construction of cv-unqualified object types (See Table 30 type C and pointer variable c as well as Table 31 expressions "a.construct(c, args)" and "a.destroy(c)"), therefore a conforming implementation needs to effectively construct an object pointer that holds an object of type remove_cv_T<U> and similarly destroy such an object. Albeit it seems to be an artificial restriction to construct and destroy only non-cv-qualified object types, this is, if any, a different issue. But given this current state, the wording for allocate_shared needs to make a special wording dance via remove_cv_T<U>. For construct the existing wording prevents to speak about that detail by using the more indirect phrase "where pv points to storage suitable to hold an object of type U", but since object types U and const U have exactly the same storage and alignment requirements, this sentence is correct for remove_cv_T<U> as well.

[2018-08-23 Batavia Issues processing]

Status to Tentatively Ready.

Proposed resolution:

This resolution is relative to N4750.

  1. Edit 23.11.3.6 [util.smartptr.shared.create] as indicated:

    template<class T, ...>
    shared_ptr<T> make_shared(args);
    template<class T, class A, ...>
    shared_ptr<T> allocate_shared(const A& a, args);
    

    […]

    -7- Remarks:

    1. […]

    2. (7.9) — When the lifetime of the object managed by the return value ends, or when the initialization of an array element throws an exception, the initialized elements are destroyed in the reverse order of their original construction.

    3. (7.?) — When a (sub)object of a non-array type U that was initialized by make_shared is to be destroyed, it is destroyed via the expression pv->~U() where pv points to that object of type U.

    4. (7.?) — When a (sub)object of a non-array type U that was initialized by allocate_shared is to be destroyed, it is destroyed via the expression allocator_traits<A2>::destroy(a2, pv) where pv points to that object of type remove_cv_t<U> and a2 of type A2 is a rebound copy of the allocator a passed to allocate_shared such that its value_type is remove_cv_t<U>.


3025(i). Map-like container deduction guides should use pair<Key, T>, not pair<const Key, T>

Section: 26.4.4.1 [map.overview], 26.4.5.1 [multimap.overview], 26.5.4.1 [unord.map.overview], 26.5.5.1 [unord.multimap.overview] Status: Tentatively Ready Submitter: Ville Voutilainen Opened: 2017-10-08 Last modified: 2018-08-27

Priority: 2

View all other issues in [map.overview].

View all issues with Tentatively Ready status.

Discussion:

With the deduction guides as specified currently, code like this doesn't work:

map m{pair{1, 1}, {2, 2}, {3, 3}};

Same problem occurs with multimap, unordered_map and unordered_multimap. The problem is in deduction guides like

template<class Key, class T, class Compare = less<Key>,
          class Allocator = allocator<pair<const Key, T>>>
map(initializer_list<pair<const Key, T>>, Compare = Compare(),
    Allocator = Allocator()) -> map<Key, T, Compare, Allocator>;

The pair<const Key, T> is not matched by a pair<int, int>, because int can't match a const Key. Dropping the const from the parameter of the deduction guide makes it work with no loss of functionality.

[2017-11-03, Zhihao Yuan comments]

The fix described here prevents

std::map m2{m0.begin(), m0.end()};

from falling back to direct-non-list-initialization. Treating a uniform initialization with >1 clauses of the same un-cvref type as std::initializer_list is the only consistent interpretation I found so far.

[2017-11 Albuquerque Wednesday night issues processing]

Priority set to 2

[2018-08-23 Batavia Issues processing]

Status to Tentatively Ready

Proposed resolution:

This wording is relative to N4687.

  1. Change 26.4.4.1 [map.overview] p3, class template map synopsis, as indicated:

    […]
    template<class Key, class T, class Compare = less<Key>,
             class Allocator = allocator<pair<const Key, T>>>
      map(initializer_list<pair<const Key, T>>, Compare = Compare(), Allocator = Allocator())
        -> map<Key, T, Compare, Allocator>;
    […]
    template<class Key, class T, class Allocator>
      map(initializer_list<pair<const Key, T>>, Allocator) -> map<Key, T, less<Key>, Allocator>;
    […]
    
  2. Change 26.4.5.1 [multimap.overview] p3, class template multimap synopsis, as indicated:

    […]
    template<class Key, class T, class Compare = less<Key>,
             class Allocator = allocator<pair<const Key, T>>>
      multimap(initializer_list<pair<const Key, T>>, Compare = Compare(), Allocator = Allocator())
        -> multimap<Key, T, Compare, Allocator>;
    […]
    template<class Key, class T, class Allocator>
      multimap(initializer_list<pair<const Key, T>>, Allocator)
        -> multimap<Key, T, less<Key>, Allocator>;
    […]
    
  3. Change 26.5.4.1 [unord.map.overview] p3, class template unordered_map synopsis, as indicated:

    […]
    template<class Key, class T, class Hash = hash<Key>,
             class Pred = equal_to<Key>, class Allocator = allocator<pair<const Key, T>>>
      unordered_map(initializer_list<pair<const Key, T>>, typename see below::size_type = see below, Hash = Hash(),
                    Pred = Pred(), Allocator = Allocator())
        -> unordered_map<Key, T, Hash, Pred, Allocator>;
    […]
    template<class Key, class T, typename Allocator>
      unordered_map(initializer_list<pair<const Key, T>>, typename see below::size_type,
                    Allocator)
        -> unordered_map<Key, T, hash<Key>, equal_to<Key>, Allocator>;
    
    template<class Key, class T, typename Allocator>
      unordered_map(initializer_list<pair<const Key, T>>, Allocator)
        -> unordered_map<Key, T, hash<Key>, equal_to<Key>, Allocator>;
    
    template<class Key, class T, class Hash, class Allocator>
      unordered_map(initializer_list<pair<const Key, T>>, typename see below::size_type, Hash,
                    Allocator)
        -> unordered_map<Key, T, Hash, equal_to<Key>, Allocator>;
    […]
    
  4. Change 26.5.5.1 [unord.multimap.overview] p3, class template unordered_multimap synopsis, as indicated:

    […]
    template<class Key, class T, class Hash = hash<Key>,
             class Pred = equal_to<Key>, class Allocator = allocator<pair<const Key, T>>>
      unordered_multimap(initializer_list<pair<const Key, T>>,
                         typename see below::size_type = see below,
                         Hash = Hash(), Pred = Pred(), Allocator = Allocator())
        -> unordered_multimap<Key, T, Hash, Pred, Allocator>;
    […]
    template<class Key, class T, typename Allocator>
      unordered_multimap(initializer_list<pair<const Key, T>>, typename see below::size_type,
                         Allocator)
        -> unordered_multimap<Key, T, hash<Key>, equal_to<Key>, Allocator>;
    
    template<class Key, class T, typename Allocator>
      unordered_multimap(initializer_list<pair<const Key, T>>, Allocator)
        -> unordered_multimap<Key, T, hash<Key>, equal_to<Key>, Allocator>;
    
    template<class Key, class T, class Hash, class Allocator>
      unordered_multimap(initializer_list<pair<const Key, T>>, typename see below::size_type,
                         Hash, Allocator)
        -> unordered_multimap<Key, T, Hash, equal_to<Key>, Allocator>;
    […]
    

3031(i). Algorithms and predicates with non-const reference arguments

Section: 28.7 [alg.sorting] Status: Tentatively Ready Submitter: Jonathan Wakely Opened: 2017-11-08 Last modified: 2018-08-27

Priority: 2

View all other issues in [alg.sorting].

View all issues with Tentatively Ready status.

Discussion:

This doesn't compile with any major implementation:

int i[1] = { };
std::stable_sort(i, i, [](int& x, int& y) { return x < y; });

The problem is that the Compare expects non-const references. We say "It is assumed that comp will not apply any non-constant function through the dereferenced iterator" But that isn't sufficient to forbid the example.

My first thought was to modify [alg.sorting] to make the Compare requirements use comp(as_const(x), as_const(x)) but that would get very verbose to add to every expression using comp.

[2017-11 Albuquerque Wednesday night issues processing]

Priority set to 2; Jonathan to improve the statement of the problem.

[2018-02 David Jones provided this truly awful example:]

#include <algorithm>
#include <iostream>
#include <vector>

struct Base {
    Base(int value) : v(value) {}
    friend bool operator<(const Base& l, const Base& r) { return l.v < r.v; }
    int v;
};

struct Derived : public Base {
    using Base::Base;
    bool operator<(const Derived& o) /* no const here */ { return v > o.v; }
};

int main(void) {
    std::vector<Base> b = {{1}, {5}, {0}, {3}};
    std::vector<Derived> d = {{0}, {1}, {3}, {5}};

    std::cout << std::lower_bound(d.begin(), d.end(), 4)->v << std::endl;

    std::sort(b.begin(), b.end());
    for (const auto &x : b) std::cout << x.v << " ";
    std::cout << std::endl;

    std::sort(d.begin(), d.end());
    for (const auto &x : d) std::cout << x.v << " ";
    std::cout << std::endl;
}

libc++:
=====
$ bin/clang++ -std=c++11 -stdlib=libc++ tmp/ex.cc && ./a.out
5
0 1 3 5 
0 1 3 5 
=====

libstdc++:
=====
$ bin/clang++ -std=c++11 -stdlib=libstdc++ tmp/ex.cc && ./a.out
0
0 1 3 5 
5 3 1 0 
=====

[2018-08 Batavia Monday issue discussion]

Tim to provide wording; status to 'Open'

[ 2018-08-20, Tim adds P/R based on Batavia discussion.]

Similar to the Ranges TS design, the P/R below requires Predicate, BinaryPredicate, and Compare to accept all mixes of const and non-const arguments.

[2018-08-23 Batavia Issues processing]

Status to Tentatively Ready after minor wording nit (corrected in place)

Proposed resolution:

This wording is relative to N4762.

  1. Edit 28.3 [algorithms.requirements] p6-7 as indicated:

    -6- The Predicate parameter is used whenever an algorithm expects a function object (23.14 [function.objects]) that, when applied to the result of dereferencing the corresponding iterator, returns a value testable as true. In other words, if an algorithm takes Predicate pred as its argument and first as its iterator argument with value type T, it should work correctly in the construct pred(*first) contextually converted to bool (7 [conv]). The function object pred shall not apply any non-constant function through the dereferenced iterator. Given a glvalue u of type (possibly const) T that designates the same object as *first, pred(u) shall be a valid expression that is equal to pred(*first).

    -7- The BinaryPredicate parameter is used whenever an algorithm expects a function object that when applied to the result of dereferencing two corresponding iterators or to dereferencing an iterator and type T when T is part of the signature returns a value testable as true. In other words, if an algorithm takes BinaryPredicate binary_pred as its argument and first1 and first2 as its iterator arguments with respective value types T1 and T2, it should work correctly in the construct binary_pred(*first1, *first2) contextually converted to bool (7 [conv]). Unless otherwise specified, BinaryPredicate always takes the first iterator's value_type as its first argument, that is, in those cases when T value is part of the signature, it should work correctly in the construct binary_pred(*first1, value) contextually converted to bool (7 [conv]). binary_pred shall not apply any non-constant function through the dereferenced iterators. Given a glvalue u of type (possibly const) T1 that designates the same object as *first1, and a glvalue v of type (possibly const) T2 that designates the same object as *first2, binary_pred(u, *first2), binary_pred(*first1, v), and binary_pred(u, v) shall each be a valid expression that is equal to binary_pred(*first1, *first2), and binary_pred(u, value) shall be a valid expression that is equal to binary_pred(*first1, value).

  2. Edit 28.7 [alg.sorting] p2 as indicated:

    Compare is a function object type (23.14 [function.objects]) that meets the requirements for a template parameter named BinaryPredicate (28.3 [algorithms.requirements]). The return value of the function call operation applied to an object of type Compare, when contextually converted to bool (7 [conv]), yields true if the first argument of the call is less than the second, and false otherwise. Compare comp is used throughout for algorithms assuming an ordering relation. It is assumed that comp will not apply any non-constant function through the dereferenced iterator.


3037(i). polymorphic_allocator and incomplete types

Section: 23.12.3 [mem.poly.allocator.class] Status: Tentatively Ready Submitter: Casey Carter Opened: 2017-11-15 Last modified: 2018-08-27

Priority: 2

View other active issues in [mem.poly.allocator.class].

View all other issues in [mem.poly.allocator.class].

View all issues with Tentatively Ready status.

Discussion:

polymorphic_allocator can trivially support the allocator completeness requirements (20.5.3.5.1 [allocator.requirements.completeness]) just as does the default allocator. Doing so imposes no implementation burden, and enables pmr::forward_list, pmr::list, and pmr::vector to support incomplete types as do the non-pmr equivalents.

[2018-01; Priority set to 2 after mailing list discussion]

[2018-08-23 Batavia Issues processing]

Status to Tentatively Ready

Proposed resolution:

Wording relative to N4700.

  1. Add a new paragraph in 23.12.3 [mem.poly.allocator.class] after para 1:

    1 A specialization of class template pmr::polymorphic_allocator conforms to the Allocator requirements [...]

    -?- All specializations of class template pmr::polymorphic_allocator satisfy the allocator completeness requirements (20.5.3.5.1 [allocator.requirements.completeness]).


3038(i). polymorphic_allocator::allocate should not allow integer overflow to create vulnerabilities

Section: 23.12.3.2 [mem.poly.allocator.mem] Status: Tentatively Ready Submitter: Billy O'Neal III Opened: 2017-11-16 Last modified: 2018-08-27

Priority: 2

View other active issues in [mem.poly.allocator.mem].

View all other issues in [mem.poly.allocator.mem].

View all issues with Tentatively Ready status.

Discussion:

At the moment polymorphic_allocator is specified to do sizeof(T) * n directly; this may allow an attacker to cause this calculation to overflow, resulting in allocate() not meeting its postcondition of returning a buffer suitable to store n copies of T; this is a common bug described in CWE-190.

Making this into a saturating multiply should be sufficient to avoid this problem; any memory_resource underneath polymorphic_allocator is going to have to throw bad_alloc (or another exception) for a request of SIZE_MAX.

(There's also a minor editorial thing here that Returns should be Effects)

[2018-06 Rapperswil Thursday issues processing]

Consensus was that the overflow should be detected and an exception thrown rather than leaving that to the underlying memory resource. Billy to reword, and then get feedback on the reflector. Status to Open.

Previous resolution [SUPERSEDED]:

Wording relative to N4700.

  1. Edit 23.12.3.2 [mem.poly.allocator.mem] as indicated:

    Tp* allocate(size_t n);
    

    -1- ReturnsEffects: Equivalent to

    return static_cast<Tp*>(memory_rsrc->allocate(SIZE_MAX / sizeof(Tp) < n ? SIZE_MAX : n * sizeof(Tp), alignof(Tp)));
    

[2018-08-23 Batavia Issues processing]

Status to Tentatively Ready with updated wording

Previous resolution [SUPERSEDED]:

Wording relative to N4762.

  1. Edit 23.12.3.2 [mem.poly.allocator.mem] as indicated:

    Tp* allocate(size_t n);
    

    -1- Effects: If SIZE_MAX / sizeof(Tp) < n, throws length_error, then Eequivalent to:

    return static_cast<Tp*>(memory_rsrc->allocate(n * sizeof(Tp), alignof(Tp)));
    

Proposed resolution:

Wording relative to N4762.

  1. Edit 23.12.3.2 [mem.poly.allocator.mem] as indicated:

    Tp* allocate(size_t n);
    

    -1- Effects: If SIZE_MAX / sizeof(Tp) < n, throws length_error. Otherwise Eequivalent to:

    return static_cast<Tp*>(memory_rsrc->allocate(n * sizeof(Tp), alignof(Tp)));
    

3065(i). LWG 2989 missed that all path's other operators should be hidden friends as well

Section: 30.11.7.7 [fs.path.nonmember] Status: Tentatively Ready Submitter: Billy O'Neal III Opened: 2018-02-13 Last modified: 2018-08-27

Priority: 2

View all issues with Tentatively Ready status.

Discussion:

Consider the following program:

// See godbolt link
#include <assert.h>
#include <string>
#include <filesystem>

using namespace std;
using namespace std::filesystem;

int main() {
  bool b = L"a//b" == std::string("a/b");
  assert(b); // passes. What?!
  return b;
}

L"a" gets converted into a path, and the string gets converted into a path, and then those paths are compared for equality. But path equality comparison doesn't work anything like string equality comparison, leading to surprises.

path's other operators should be made hidden friends as well, so that one side or the other of a given operator is of type path before those conversions apply.

[2018-02-20, Priority set to 2 after mailing list discussion]

[2018-08-23 Batavia Issues processing]

Status to Tentatively Ready

Proposed resolution:

This wording is relative to N4713.

All drafting notes from LWG 2989 apply here too.

  1. Modify 30.11.5 [fs.filesystem.syn], header <filesystem> synopsis, as indicated:

    […]
    // 30.11.7.7 [fs.path.nonmember], path non-member functions
    void swap(path& lhs, path& rhs) noexcept;
    size_t hash_value(const path& p) noexcept;
    
    bool operator==(const path& lhs, const path& rhs) noexcept;
    bool operator!=(const path& lhs, const path& rhs) noexcept;
    bool operator< (const path& lhs, const path& rhs) noexcept;
    bool operator<=(const path& lhs, const path& rhs) noexcept;
    bool operator> (const path& lhs, const path& rhs) noexcept;
    bool operator>=(const path& lhs, const path& rhs) noexcept;
    
    path operator/ (const path& lhs, const path& rhs);
    […]
    
  2. Modify 30.11.7.7 [fs.path.nonmember] as indicated:

    […]
    friend bool operator< (const path& lhs, const path& rhs) noexcept;
    […]
    friend bool operator<=(const path& lhs, const path& rhs) noexcept;
    […]
    friend bool operator> (const path& lhs, const path& rhs) noexcept;
    […]
    friend bool operator>=(const path& lhs, const path& rhs) noexcept;
    […]
    friend bool operator==(const path& lhs, const path& rhs) noexcept;
    […]
    friend bool operator!=(const path& lhs, const path& rhs) noexcept;
    […]
    friend path operator/ (const path& lhs, const path& rhs);
    […]
    
  3. Modify 30.11.7 [fs.class.path], class path synopsis, as indicated:

    class path {
    public:
      […]
      // 30.11.7.4.5 [fs.path.modifiers], modifiers
      […]
      
      // 30.11.7.7 [fs.path.nonmember], non-member operators
      friend bool operator< (const path& lhs, const path& rhs) noexcept;
      friend bool operator<=(const path& lhs, const path& rhs) noexcept;
      friend bool operator> (const path& lhs, const path& rhs) noexcept;
      friend bool operator>=(const path& lhs, const path& rhs) noexcept;
      friend bool operator==(const path& lhs, const path& rhs) noexcept;
      friend bool operator!=(const path& lhs, const path& rhs) noexcept;
      
      friend path operator/ (const path& lhs, const path& rhs);
      
      // 30.11.7.4.6 [fs.path.native.obs], native format observers
      […]
    };
    

3096(i). path::lexically_relative is confused by trailing slashes

Section: 30.11.7.4.11 [fs.path.gen] Status: Tentatively Ready Submitter: Jonathan Wakely Opened: 2018-04-04 Last modified: 2018-08-27

Priority: 2

View other active issues in [fs.path.gen].

View all other issues in [fs.path.gen].

View all issues with Tentatively Ready status.

Discussion:

filesystem::proximate("/dir", "/dir/") returns "." when "/dir" exists, and ".." otherwise. It should always be "." because whether it exists shouldn't matter.

The problem is in filesystem::path::lexically_relative, as shown by:

path("/dir").lexically_relative("/dir/.");  // yields ""
path("/dir").lexically_relative("/dir/");   // yields ".."

The two calls should yield the same result, and when iteration of a path with a trailing slash gave "." as the final element they did yield the same result. In the final C++17 spec the trailing slash produces an empty filename in the iteration sequence, and lexically_relative doesn't handle that correctly.

[2018-04-10, Jonathan comments]

There are more inconsistencies with paths that are "obviously" equivalent to the human reader:

path("a/b/c").lexically_relative("a/b/c")    // yields "."
path("a/b/c").lexically_relative("a/b/c/")   // yields ".."
path("a/b/c").lexically_relative("a/b/c/.")  // yields ""
path("a/b/c/").lexically_relative("a/b/c")   // yields ""
path("a/b/c/.").lexically_relative("a/b/c")  // yields "."
path("a/b/c/.").lexically_relative("a/b/c/") // yields "../."

I think the right solution is:

  1. when counting [b, base.end()) in bullet (4.2) handle empty filename elements (which can only occur as the last element, due to a trailing slash) equivalently to dot elements; and

  2. add a new condition for the case where n == 0 and [a, end()) contains no non-empty elements, i.e. the paths are equivalent except for final dots or a final slash, which don't introduce any relative difference between the paths.

[2018-06-18 after reflector discussion]

Priority set to 2

[2018-08-23 Batavia Issues processing]

Status to Tentatively Ready

Proposed resolution:

This wording is relative to N4727.

  1. Edit 30.11.7.4.11 [fs.path.gen] as indicated:

    path lexically_relative(const path& base) const;
    

    -3- Returns: *this made relative to base. Does not resolve (30.11.7 [fs.class.path]) symlinks. Does not first normalize (30.11.7.1 [fs.path.generic]) *this or base.

    -4- Effects: If root_name() != base.root_name() is true or is_absolute() != base.is_absolute() is true or !has_root_directory() && base.has_root_directory() is true, returns path(). Determines the first mismatched element of *this and base as if by:

    auto [a, b] = mismatch(begin(), end(), base.begin(), base.end());
    

    Then,

    1. (4.1) — if a == end() and b == base.end(), returns path("."); otherwise

    2. (4.2) — let n be the number of filename elements in [b, base.end()) that are not dot or dot-dot or empty, minus the number that are dot-dot. If n<0, returns path(); otherwise

    3. (4.?) — if n == 0 and (a == end() || a->empty()), returns path("."); otherwise

    4. (4.3) — returns an object of class path that is default-constructed, followed by […]


3106(i). nothrow should be inline constexpr rather that extern const

Section: 21.6.1 [new.syn] Status: Tentatively NAD Submitter: Antony Polukhin Opened: 2018-04-25 Last modified: 2018-08-27

Priority: 2

View all issues with Tentatively NAD status.

Discussion:

std::nothrow in [new.syn] is declared as 'extern const nothrow_t nothrow;'. Unfortunately this declaration requires linking with Standard Library (which does not work well on GCC with -nostdlib flag). Moreover the declaration differs from other Standard Library tags that are 'inline constexpr'.

[2018-06-18 after reflector discussion]

Priority set to 2

[2018-08-23 Batavia Issues processing]

Status to Tentatively NAD - if we had a status 'Wont Fix' that would be correct.

This is an ABI break for most implementations, and people can define their own variable of type std::nothrow_t if they want a constexpr one.

Proposed resolution:

This wording is relative to N4741.

  1. Edit 21.6.1 [new.syn] as indicated:

    struct nothrow_t { explicit nothrow_t() = default; };
    extern constinline constexpr nothrow_t nothrow;
    

3122(i). __cpp_lib_chrono_udls was accidentally dropped

Section: 21.3.1 [support.limits.general] Status: Tentatively Ready Submitter: Stephan T. Lavavej Opened: 2018-06-14 Last modified: 2018-06-24

Priority: 0

View other active issues in [support.limits.general].

View all other issues in [support.limits.general].

View all issues with Tentatively Ready status.

Discussion:

Between P0941R0 and P0941R1/P0941R2, the feature-test macro __cpp_lib_chrono_udls was dropped. It wasn't mentioned in the changelog, and Jonathan Wakely and I believe that this was unintentional.

[2018-06-23 Moved to Tentatively Ready after 5 positive votes on c++std-lib.]

Proposed resolution:

This wording is relative to the post-Rapperswil 2018 working draft.

In 21.3.1 [support.limits.general], "Table ??? - Standard library feature-test macros", add the following row:

Table ??? — Standard library feature-test macros
Macro name Value Headers
[…]
__cpp_lib_chrono_udls 201304L <chrono>
[…]

3127(i). basic_osyncstream::rdbuf needs a const_cast

Section: 30.10.3.1 [syncstream.osyncstream.overview] Status: Tentatively Ready Submitter: Tim Song Opened: 2018-06-29 Last modified: 2018-07-20

Priority: 0

View all issues with Tentatively Ready status.

Discussion:

The current specification of basic_osyncstream::rdbuf() is

    syncbuf_type* rdbuf() const noexcept { return &sb; }

This is ill-formed because the exposition-only member sb is const inside this const member function, but the return type is a pointer to non-const syncbuf_type. It needs to cast away the constness, consistent with the other streams with embedded stream buffers (such as string and file streams).

[2018-07-20 Status set to Tentatively Ready after five positive votes on the reflector.]

Proposed resolution:

This wording is relative to N4750.

  1. Change 30.10.3.1 [syncstream.osyncstream.overview], class template basic_osyncstream synopsis, as indicated:

    namespace std {
      template<class charT, class traits, class Allocator>
      class basic_osyncstream : public basic_ostream<charT, traits> {
      public:
        […]
    
        // 30.10.3.4 [syncstream.osyncstream.members], member functions
        void emit();
        streambuf_type* get_wrapped() const noexcept;
        syncbuf_type* rdbuf() const noexcept { return const_cast<syncbuf_type*>(&sb); }
        […]
      };
    }
    

3128(i). strstream::rdbuf needs a const_cast

Section: D.8.5.3 [depr.strstream.oper] Status: Tentatively Ready Submitter: Tim Song Opened: 2018-06-30 Last modified: 2018-07-20

Priority: 0

View all issues with Tentatively Ready status.

Discussion:

strstream::rdbuf has the same issue with a missing const_cast on &sb.

Somewhat amusingly, istrstream::rdbuf and ostrstream::rdbuf got this right, but each with a different style (see issue 252).

[2018-07-20 Status to Tentatively Ready after five positive votes on the reflector.]

Proposed resolution:

This wording is relative to N4750.

  1. Change D.8.5.3 [depr.strstream.oper] p1 as indicated:

    strstreambuf* rdbuf() const;
    

    -1- Returns: const_cast<strstreambuf*>(&sb).


3129(i). regex_token_iterator constructor uses wrong pointer arithmetic

Section: 31.12.2.1 [re.tokiter.cnstr] Status: Tentatively Ready Submitter: Tim Song Opened: 2018-06-30 Last modified: 2018-07-20

Priority: 0

View all other issues in [re.tokiter.cnstr].

View all issues with Tentatively Ready status.

Discussion:

The specification of regex_token_iterator for the overload taking a const int (&submatchs)[N] uses the range [&submatches, &submatches + N). This is obviously incorrect; we want to perform pointer arithmetic on a pointer to the first element of that array, not a pointer to the whole array.

[2018-07-20 Status to Tentatively Ready after five positive votes on the reflector.]

Proposed resolution:

This wording is relative to N4750.

  1. Change 31.12.2.1 [re.tokiter.cnstr] p3 as indicated:

    regex_token_iterator(BidirectionalIterator a, BidirectionalIterator b,
                         const regex_type& re,
                         int submatch = 0,
                         regex_constants::match_flag_type m = regex_constants::match_default);
    
    regex_token_iterator(BidirectionalIterator a, BidirectionalIterator b,
                         const regex_type& re,
                         const vector<int>& submatches,
                         regex_constants::match_flag_type m = regex_constants::match_default);
    
    regex_token_iterator(BidirectionalIterator a, BidirectionalIterator b,
                         const regex_type& re,
                         initializer_list<int> submatches,
                         regex_constants::match_flag_type m = regex_constants::match_default);
    
    template<size_t N>
      regex_token_iterator(BidirectionalIterator a, BidirectionalIterator b,
                           const regex_type& re,
                           const int (&submatches)[N],
                           regex_constants::match_flag_type m = regex_constants::match_default);
    

    -2- Requires: […]

    -3- Effects: The first constructor initializes the member subs to hold the single value submatch. The second constructor initializes the member subs to hold a copy of the argument submatches. The second, third and fourth constructors initialize the member subs to hold a copy of the sequence of integer values pointed to by the iterator range [submatches.begin(), submatches.end()) and [&submatches, &submatches + N), respectively[begin(submatches), end(submatches)).

    -4- […]


3130(i). §[input.output] needs many addressof

Section: 30 [input.output] Status: Tentatively Ready Submitter: Tim Song Opened: 2018-06-30 Last modified: 2018-07-20

Priority: 0

View other active issues in [input.output].

View all other issues in [input.output].

View all issues with Tentatively Ready status.

Discussion:

There are 27 instances of &sb and one instance of &rhs in Clause 30 [input.output], each of which needs to use addressof because the operand has a user-provided template type parameter as an associated class and so the use of unary & is subject to ADL hijacking.

[2018-07-20 Status to Tentatively Ready after five positive votes on the reflector.]

Proposed resolution:

This wording is relative to N4750.

  1. Change 30.5.5.3 [basic.ios.members] p16 as indicated:

    basic_ios& copyfmt(const basic_ios& rhs);
    

    -16- Effects: If (this == &addressof(rhs)) does nothing. […]

  2. Change 30.8.3.1 [istringstream.cons] as indicated:

    explicit basic_istringstream(ios_base::openmode which);
    

    -1- Effects: Constructs an object of class basic_istringstream<charT, traits>, initializing the base class with basic_istream<charT, traits>(&addressof(sb)) (30.7.4.1 [istream]) and initializing sb with basic_stringbuf<charT, traits, Allocator>(which | ios_base::in) (30.8.2.1 [stringbuf.cons]).

    explicit basic_istringstream(
      const basic_string<charT, traits, Allocator>& str,
      ios_base::openmode which = ios_base::in);
    

    -2- Effects: Constructs an object of class basic_istringstream<charT, traits>, initializing the base class with basic_istream<charT, traits>(&addressof(sb)) (30.7.4.1 [istream]) and initializing sb with basic_stringbuf<charT, traits, Allocator>(str, which | ios_base::in) (30.8.2.1 [stringbuf.cons]).

    basic_istringstream(basic_istringstream&& rhs);
    

    -3- Effects: Move constructs from the rvalue rhs. This is accomplished by move constructing the base class, and the contained basic_stringbuf. Next basic_istream<charT, traits>::set_rdbuf(&addressof(sb)) is called to install the contained basic_stringbuf.

  3. Change 30.8.3.3 [istringstream.members] p1 as indicated:

    basic_stringbuf<charT, traits, Allocator>* rdbuf() const;
    

    -1- Returns: const_cast<basic_stringbuf<charT, traits, Allocator>*>(&addressof(sb)).

  4. Change 30.8.4.1 [ostringstream.cons] as indicated:

    explicit basic_ostringstream(ios_base::openmode which);
    

    -1- Effects: Constructs an object of class basic_ostringstream<charT, traits>, initializing the base class with basic_ostream<charT, traits>(&addressof(sb)) (30.7.5.1 [ostream]) and initializing sb with basic_stringbuf<charT, traits, Allocator>(which | ios_base::out) (30.8.2.1 [stringbuf.cons]).

    explicit basic_ostringstream(
      const basic_string<charT, traits, Allocator>& str,
      ios_base::openmode which = ios_base::out);
    

    -2- Effects: Constructs an object of class basic_ostringstream<charT, traits>, initializing the base class with basic_ostream<charT, traits>(&addressof(sb)) (30.7.5.1 [ostream]) and initializing sb with basic_stringbuf<charT, traits, Allocator>(str, which | ios_base::out) (30.8.2.1 [stringbuf.cons]).

    basic_ostringstream(basic_ostringstream&& rhs);
    

    -3- Effects: Move constructs from the rvalue rhs. This is accomplished by move constructing the base class, and the contained basic_stringbuf. Next basic_ostream<charT, traits>::set_rdbuf(&addressof(sb)) is called to install the contained basic_stringbuf.

  5. Change 30.8.4.3 [ostringstream.members] p1 as indicated:

    basic_stringbuf<charT, traits, Allocator>* rdbuf() const;
    

    -1- Returns: const_cast<basic_stringbuf<charT, traits, Allocator>*>(&addressof(sb)).

  6. Change 30.8.5.1 [stringstream.cons] as indicated:

    explicit basic_stringstream(ios_base::openmode which);
    

    -1- Effects: Constructs an object of class basic_stringstream<charT, traits>, initializing the base class with basic_iostream<charT, traits>(&addressof(sb)) (30.7.4.6.1 [iostream.cons]) and initializing sb with basic_stringbuf<charT, traits, Allocator>(which).

    explicit basic_stringstream(
      const basic_string<charT, traits, Allocator>& str,
      ios_base::openmode which = ios_base::out | ios_base::in);
    

    -2- Effects: Constructs an object of class basic_stringstream<charT, traits>, initializing the base class with basic_iostream<charT, traits>(&addressof(sb)) (30.7.4.6.1 [iostream.cons]) and initializing sb with basic_stringbuf<charT, traits, Allocator>(str, which).

    basic_stringstream(basic_stringstream&& rhs);
    

    -3- Effects: Move constructs from the rvalue rhs. This is accomplished by move constructing the base class, and the contained basic_stringbuf. Next basic_istream<charT, traits>::set_rdbuf(&addressof(sb)) is called to install the contained basic_stringbuf.

  7. Change 30.8.5.3 [stringstream.members] p1 as indicated:

    basic_stringbuf<charT, traits, Allocator>* rdbuf() const;
    

    -1- Returns: const_cast<basic_stringbuf<charT, traits, Allocator>*>(&addressof(sb)).

  8. Change 30.9.3.1 [ifstream.cons] as indicated:

    basic_ifstream();
    

    -1- Effects: Constructs an object of class basic_ifstream<charT, traits>, initializing the base class with basic_istream<charT, traits>(&addressof(sb)) (30.7.4.1.1 [istream.cons]) and initializing sb with basic_filebuf<charT, traits>() (30.9.2.1 [filebuf.cons]).

    explicit basic_ifstream(const char* s,
                            ios_base::openmode mode = ios_base::in);
    explicit basic_ifstream(const filesystem::path::value_type* s,
                            ios_base::openmode mode = ios_base::in);  // wide systems only; see 30.9.1 [fstream.syn]
    

    -2- Effects: Constructs an object of class basic_ifstream<charT, traits>, initializing the base class with basic_istream<charT, traits>(&addressof(sb)) (30.7.4.1.1 [istream.cons]) and initializing sb with basic_filebuf<charT, traits>() (30.9.2.1 [filebuf.cons]), then calls rdbuf()->open(s, mode | ios_base::in). If that function returns a null pointer, calls setstate(failbit).

    […]

    basic_ifstream(basic_ifstream&& rhs);
    

    -4- Effects: Move constructs from the rvalue rhs. This is accomplished by move constructing the base class, and the contained basic_filebuf. Next basic_istream<charT, traits>::set_rdbuf(&addressof(sb)) is called to install the contained basic_filebuf.

  9. Change 30.9.3.3 [ifstream.members] p1 as indicated:

    basic_filebuf<charT, traits>* rdbuf() const;
    

    -1- Returns: const_cast<basic_filebuf<charT, traits>*>(&addressof(sb)).

  10. Change 30.9.4.1 [ofstream.cons] as indicated:

    basic_ofstream();
    

    -1- Effects: Constructs an object of class basic_ofstream<charT, traits>, initializing the base class with basic_ostream<charT, traits>(&addressof(sb)) (30.7.5.1.1 [ostream.cons]) and initializing sb with basic_filebuf<charT, traits>() (30.9.2.1 [filebuf.cons]).

    explicit basic_ofstream(const char* s,
                            ios_base::openmode mode = ios_base::out);
    explicit basic_ofstream(const filesystem::path::value_type* s,
                            ios_base::openmode mode = ios_base::out);  // wide systems only; see 30.9.1 [fstream.syn]
    

    -2- Effects: Constructs an object of class basic_ofstream<charT, traits>, initializing the base class with basic_ostream<charT, traits>(&addressof(sb)) (30.7.5.1.1 [ostream.cons]) and initializing sb with basic_filebuf<charT, traits>() (30.9.2.1 [filebuf.cons]), then calls rdbuf()->open(s, mode | ios_base::out). If that function returns a null pointer, calls setstate(failbit).

    […]

    basic_ofstream(basic_ofstream&& rhs);
    

    -4- Effects: Move constructs from the rvalue rhs. This is accomplished by move constructing the base class, and the contained basic_filebuf. Next basic_ostream<charT, traits>::set_rdbuf(&addressof(sb)) is called to install the contained basic_filebuf.

  11. Change 30.9.4.3 [ofstream.members] p1 as indicated:

    basic_filebuf<charT, traits>* rdbuf() const;
    

    -1- Returns: const_cast<basic_filebuf<charT, traits>*>(&addressof(sb)).

  12. Change 30.9.5.1 [fstream.cons] as indicated:

    basic_fstream();
    

    -1- Effects: Constructs an object of class basic_fstream<charT, traits>, initializing the base class with basic_iostream<charT, traits>(&addressof(sb)) (30.7.4.6.1 [iostream.cons]) and initializing sb with basic_filebuf<charT, traits>().

    explicit basic_fstream(
      const char* s,
      ios_base::openmode mode = ios_base::in | ios_base::out);
    explicit basic_fstream(
      const filesystem::path::value_type* s,
      ios_base::openmode mode = ios_base::in | ios_base::out);  // wide systems only; see 30.9.1 [fstream.syn]
    

    -2- Effects: Constructs an object of class basic_fstream<charT, traits>, initializing the base class with basic_iostream<charT, traits>(&addressof(sb)) (30.7.4.6.1 [iostream.cons]) and initializing sb with basic_filebuf<charT, traits>(), then calls rdbuf()->open(s, mode). If that function returns a null pointer, calls setstate(failbit).

    […]

    basic_fstream(basic_fstream&& rhs);
    

    -4- Effects: Move constructs from the rvalue rhs. This is accomplished by move constructing the base class, and the contained basic_filebuf. Next basic_istream<charT, traits>::set_rdbuf(&addressof(sb)) is called to install the contained basic_filebuf.

  13. Change 30.9.5.3 [fstream.members] p1 as indicated:

    basic_filebuf<charT, traits>* rdbuf() const;
    

    -1- Returns: const_cast<basic_filebuf<charT, traits>*>(&addressof(sb)).

  14. Change 30.10.3.1 [syncstream.osyncstream.overview], class template basic_osyncstream synopsis, as indicated:

    [Drafting note: The text shown below assumes the application of the proposed resolution of issue 3127.]

    namespace std {
      template<class charT, class traits, class Allocator>
      class basic_osyncstream : public basic_ostream<charT, traits> {
      public:
        […]
    
        // 30.10.3.4 [syncstream.osyncstream.members], member functions
        void emit();
        streambuf_type* get_wrapped() const noexcept;
        syncbuf_type* rdbuf() const noexcept { return const_cast<syncbuf_type*>(&addressof(sb)); }
        […]
      };
    }
    
  15. Change 30.10.3.2 [syncstream.osyncstream.cons] p1 and p4 as indicated:

    basic_osyncstream(streambuf_type* buf, const Allocator& allocator);
    

    -1- Effects: Initializes sb from buf and allocator. Initializes the base class with basic_ostream<charT, traits>(&addressof(sb)).

    -2- […]

    -3- […]

    basic_osyncstream(basic_osyncstream&& other) noexcept;
    

    -4- Effects: Move constructs the base class and sb from the corresponding subobjects of other, and calls basic_ostream<charT, traits>::set_rdbuf(&addressof(sb)).

    -5- […]


3131(i). addressof all the things

Section: 23.17.12 [time.parse], 24.3.2.7.1 [string.accessors], 24.4.2 [string.view.template], 26.2.1 [container.requirements.general], 27.2.4 [output.iterators], 27.2.6 [bidirectional.iterators], 31.7 [re.traits], 31.12.1 [re.regiter], 33.4.4.1 [thread.lock.guard] Status: Tentatively Ready Submitter: Tim Song Opened: 2018-06-30 Last modified: 2018-07-20

Priority: 0

View all issues with Tentatively Ready status.

Discussion:

Some additional instances where the library specification applies unary operator & when it should use addressof.

[2018-07-20 Status to Tentatively Ready after five positive votes on the reflector.]

Proposed resolution:

This wording is relative to N4750.

[Drafting note: Two uses of & in 27.5.1 [reverse.iterators] are not included in the wording below because the entire sentence is slated to be removed by a revision of P0896, the One Ranges Proposal.]

  1. Change 23.17.12 [time.parse] p4-5 as indicated:

    template<class charT, class traits, class Alloc, class Parsable>
      unspecified
        parse(const basic_string<charT, traits, Alloc>& fmt, Parsable& tp,
              basic_string<charT, traits, Alloc>& abbrev);
    

    -4- Remarks: This function shall not participate in overload resolution unless

    from_stream(declval<basic_istream<charT, traits>&>(), fmt.c_str(), tp, &addressof(abbrev))
    

    is a valid expression.

    -5- Returns: A manipulator that, when extracted from a basic_istream<charT, traits> is, calls from_stream(is, fmt.c_str(), tp, &addressof(abbrev)).

  2. Change 23.17.12 [time.parse] p8-9 as indicated:

    template<class charT, class traits, class Alloc, class Parsable>
      unspecified
        parse(const basic_string<charT, traits, Alloc>& fmt, Parsable& tp,
              basic_string<charT, traits, Alloc>& abbrev, minutes& offset);
    

    -8- Remarks: This function shall not participate in overload resolution unless

    from_stream(declval<basic_istream<charT, traits>&>(), fmt.c_str(), tp, &addressof(abbrev), &offset)
    

    is a valid expression.

    -9- Returns: A manipulator that, when extracted from a basic_istream<charT, traits> is, calls from_stream(is, fmt.c_str(), tp, &addressof(abbrev), &offset).

  3. Change 24.3.2.7.1 [string.accessors] p1 and p4 as indicated:

    const charT* c_str() const noexcept;
    const charT* data() const noexcept;
    

    -1- Returns: A pointer p such that p + i == &addressof(operator[](i)) for each i in [0, size()].

    -2- Complexity: Constant time.

    -3- Requires: The program shall not alter any of the values stored in the character array.

    charT* data() noexcept;
    

    -4- Returns: A pointer p such that p + i == &addressof(operator[](i)) for each i in [0, size()].

    -5- Complexity: Constant time.

    -6- Requires: The program shall not alter the value stored at p + size().

  4. Change 24.4.2.2 [string.view.iterators] p4 as indicated:

    constexpr const_iterator begin() const noexcept;
    constexpr const_iterator cbegin() const noexcept;
    

    -4- Returns: An iterator such that

    (4.1) — if !empty(), &addressof(*begin()) == data_,

    (4.2) — otherwise, an unspecified value such that [begin(), end()) is a valid range.

  5. Change 24.4.2.6 [string.view.ops] p21 and p24 as indicated:

    constexpr bool starts_with(charT x) const noexcept;
    

    -21- Effects: Equivalent to: return starts_with(basic_string_view(&addressof(x), 1));

    […]

    constexpr bool ends_with(charT x) const noexcept;
    

    -24- Effects: Equivalent to: return ends_with(basic_string_view(&addressof(x), 1));

  6. Change 24.4.2.7 [string.view.find] p5 as indicated:

    -5- Each member function of the form

    constexpr return-type F(charT c, size_type pos);
    

    is equivalent to return F(basic_string_view(&addressof(c), 1), pos);

  7. Edit 26.2.1 [container.requirements.general], Table 77 — "Container requirements", as indicated:

    Table 77 — Container requirements
    Expression Return type Operational
    semantics
    Assertion/note
    pre/post-condition
    Complexity
    […]
    (&a)->a.~X() void the destructor is applied to every element of a; any memory obtained is deallocated. linear
    […]
  8. Edit 27.2.4 [output.iterators], Table 90 — "Output iterator requirements (in addition to Iterator)", as indicated:

    Table 90 — Output iterator requirements (in addition to Iterator)
    Expression Return type Operational
    semantics
    Assertion/note
    pre/post-condition
    […]
    ++r X& &addressof(r) == &addressof(++r).
    […]
    […]
  9. Edit 27.2.6 [bidirectional.iterators], Table 92 — "Bidirectional iterator requirements (in addition to forward iterator)", as indicated:

    Table 92 — Bidirectional iterator requirements (in addition to forward iterator)
    Expression Return type Operational
    semantics
    Assertion/note
    pre/post-condition
    --r X& […]
    &addressof(r) == &addressof(--r).
    […]
  10. Change 31.7 [re.traits] p6 as indicated:

    template<class ForwardIterator>
      string_type transform(ForwardIterator first, ForwardIterator last) const;
    

    -6- Effects: As if by:

    string_type str(first, last);
    return use_facet<collate<charT>>(
      getloc()).transform(&*str.begindata(), &*str.begindata() + str.length());
    
  11. Change 31.12.1.1 [re.regiter.cnstr] p2 as indicated:

    regex_iterator(BidirectionalIterator a, BidirectionalIterator b,
                   const regex_type& re,
                   regex_constants::match_flag_type m = regex_constants::match_default);
    

    -2- Effects: Initializes begin and end to a and b, respectively, sets pregex to &addressof(re), sets flags to m, then calls regex_search(begin, end, match, *pregex, flags). If this call returns false the constructor sets *this to the end-of-sequence iterator.

  12. Change 31.12.1.3 [re.regiter.deref] p2 as indicated:

    const value_type* operator->() const;
    

    -2- Returns: &addressof(match).

  13. Change 33.4.4.1 [thread.lock.guard] p2-7 as indicated:

    explicit lock_guard(mutex_type& m);
    

    -2- Requires: If mutex_type is not a recursive mutex, the calling thread does not own the mutex m.

    -3- Effects: As if byInitializes pm with m. Calls m.lock().

    -4- Postconditions: &pm == &m

    lock_guard(mutex_type& m, adopt_lock_t);
    

    -5- Requires: The calling thread owns the mutex m.

    -6- Postconditions: &pm == &mEffects: Initializes pm with m.

    -7- Throws: Nothing.


3132(i). Library needs to ban macros named expects or ensures

Section: 20.5.4.3.2 [macro.names] Status: Tentatively Ready Submitter: Tim Song Opened: 2018-06-30 Last modified: 2018-08-10

Priority: 0

View other active issues in [macro.names].

View all other issues in [macro.names].

View all issues with Tentatively Ready status.

Discussion:

expects and ensures are not technically described as attribute-tokens when used in a contract-attribute-specifier, so the existing prohibition in 20.5.4.3.2 [macro.names] doesn't apply to them.

The remaining special identifiers used by the contract attributes are all already covered by existing wording: assert is also a library name so falls under p1, default is a keyword, and both axiom and audit were added to Table 4.

[2018-07-20 Status to Tentatively Ready after five positive votes on the reflector.]

Proposed resolution:

This wording is relative to N4762.

  1. Change 20.5.4.3.2 [macro.names] p2 as indicated:

    -2- A translation unit shall not #define or #undef names lexically identical to keywords, to the identifiers listed in Table 4, or to the attribute-tokens described in 10.6 [dcl.attr], or to the identifiers expects or ensures.


3134(i). [fund.ts.v3] LFTSv3 contains extraneous [meta] variable templates that should have been deleted by P09961

Section: 3.3.1 [fund.ts.v3::meta.type.synop] Status: Tentatively Ready Submitter: Thomas Köppe Opened: 2018-07-02 Last modified: 2018-07-20

Priority: 0

View other active issues in [fund.ts.v3::meta.type.synop].

View all other issues in [fund.ts.v3::meta.type.synop].

View all issues with Tentatively Ready status.

Discussion:

Addresses: fund.ts.v3

The LFTSv3 prospective-working-paper N4758 lists a large number of type trait variable templates in [meta.type.synop] that are duplicates of corresponding ones in C++17. The paper P0996R1 that was meant to rebase the LFTS on C++17 appears to have missed them.

[2018-07-20 Status to Tentatively Ready after five positive votes on the reflector.]

Proposed resolution:

This wording is relative to N4758.

  1. Delete from 3.3.1 [fund.ts.v3::meta.type.synop] all variable templates starting at is_void_v up to and including is_convertible_v as indicated:

    #include <type_traits>
    
    namespace std::experimental {
    inline namespace fundamentals_v3 {
    
      // See C++17 §23.15.4.1, primary type categories
      template <class T> constexpr bool is_void_v
        = is_void<T>::value;
      […]
      template <class From, class To> constexpr bool is_convertible_v
        = is_convertible<From, To>::value;
    
      // 3.3.2, Other type transformations
      template <class> class invocation_type; // not defined
      […]
    } // inline namespace fundamentals_v3
    } // namespace std::experimental
    

3137(i). Header for __cpp_lib_to_chars

Section: 21.3.1 [support.limits.general] Status: Tentatively Ready Submitter: S. B.Tam Opened: 2018-07-03 Last modified: 2018-07-20

Priority: 0

View other active issues in [support.limits.general].

View all other issues in [support.limits.general].

View all issues with Tentatively Ready status.

Discussion:

After acceptance of P0941R2 into the working draft, in [support.limits.general], __cpp_lib_to_chars is required to be in <utility>. Since the relevant feature (std::to_chars and std::from_chars) is now in the header <charconv>, should the macro be defined in <charconv> instead of <utility>?

[Marshall provides P/R and context]

std::to_chars, etc were originally proposed for the header <utility> and SD-6 reflected that. Somewhere along the way, they was put into their own header <charconv>, but the document was never updated to reflect that.

When these macros were added to the standard, the (now incorrect) value was copied as well.

[2018-07-20 Status to Tentatively Ready after five positive votes on the reflector.]

Proposed resolution:

This wording is relative to (the Rapperswil post-mailing standard).

Change 21.3.1 [support.limits.general] (Table 35) as indicated:

Macro nameValueHeader(s)
__cpp_lib_to_chars201611L<charconvutility>

3140(i). COMMON_REF is unimplementable as specified

Section: 23.15.7.6 [meta.trans.other] Status: Tentatively Ready Submitter: Casey Carter Opened: 2018-07-07 Last modified: 2018-10-07

Priority: 0

View other active issues in [meta.trans.other].

View all other issues in [meta.trans.other].

View all issues with Tentatively Ready status.

Discussion:

23.15.7.6 [meta.trans.other]/3.2 states:

[Let] XREF(A) denote a unary class template T such that T<U> denotes the same type as U with the addition of A’s cv and reference qualifiers, for a non-reference cv-unqualified type U,
which is nonsensical: a specialization of a class template cannot possibly be a cv-qualified type or reference type. XREF(A) must be a unary alias template.

[2018-09-11; Status set to Tentatively Ready after five positive votes on the reflector]

Proposed resolution:

This wording is relative to N4762.

Change 23.15.7.6 [meta.trans.other] as indicated:

-3- Let:

(3.1) — CREF(A) be add_lvalue_reference_t<const remove_reference_t<A>>,

(3.2) — XREF(A) denote a unary classalias template T such that T<U> denotes the same type as U with the addition of A’s cv and reference qualifiers, for a non-reference cv-unqualified type U,

(3.3) — COPYCV(FROM, TO) be an alias for type TO with the addition of FROM’s top-level cv-qualifiers. [Example: COPYCV(const int, volatile short) is an alias for const volatile short. —end example]


3145(i). file_clock breaks ABI for C++17 implementations

Section: 23.17.7.5 [time.clock.file] Status: Tentatively Ready Submitter: Billy Robert O'Neal III Opened: 2018-07-26 Last modified: 2018-08-27

Priority: 1

View all issues with Tentatively Ready status.

Discussion:

It was pointed out in one of Eric's changes to libc++ here that P0355 adds file_clock, which is intended to be the clock used for std::filesystem::file_time_type's clock.

Unfortunately, this is an ABI break for implementations that are already shipping C++17 filesystem that did not call their clock type std::file_clock. For example, MSVC++'s is called std::filesystem::_File_time_clock.

We can keep much the same interface of P0355 by making file_clock a typedef for an unspecified type. This technically changes the associated namespaces for expressions using that clock for the sake of ADL, but I can't imagine a user who cares, as clocks aren't generally called in ADL-able expressions, durations and time_points are.

Previous resolution [SUPERSEDED]:

This wording is relative to N4750.

  1. Change 23.17.2 [time.syn], header <chrono> synopsis, as indicated:

    […]
    // 23.17.7.5 [time.clock.file], classtype file_clock
    classusing file_clock = unspecified;
    […]
    
  2. Change 23.17.7.5 [time.clock.file] as indicated:

    23.17.7.5 ClassType file_clock [time.clock.file]

  3. Change 23.17.7.5.1 [time.clock.file.overview], class file_clock synopsis, as indicated:

    namespace std::chrono {
      using file_clock = see below;
      class file_clock {
      public:
        using rep = a signed arithmetic type;
        using period = ratio<unspecified, unspecified>;
        using duration = chrono::duration<rep, period>;
        using time_point = chrono::time_point<file_clock>;
        static constexpr bool is_steady = unspecified;
        
        static time_point now() noexcept;
        
        // Conversion functions, see below
      };
    }
    

    -1- The clock file_clock is an alias for a type meeting the TrivialClock requirements (23.17.3 [time.clock.req]), uses a signed arithmetic type for file_clock::rep, and is used to create the time_point system used for file_time_type (30.11 [filesystems]). Its epoch is unspecified. [Note: The type file_clock denotes may be in a different namespace than std::chrono, such as std::filesystem. — end note]

  4. Change 23.17.7.5.2 [time.clock.file.members] as indicated:

    static time_point now();
    

    -1- Returns: A file_clock::time_point indicating the current time.

    -2- The class file_clock shalltype denoted by file_clock provides precisely one of the following two sets of static member functions: […]

[2018-07-30 Priority set to 1 after reflector discussion; wording updates based on several discussion contributions.]

Previous resolution [SUPERSEDED]:

This wording is relative to N4762.

  1. Change 23.17.2 [time.syn], header <chrono> synopsis, as indicated:

    […]
    // 23.17.7.5 [time.clock.file], classtype file_clock
    classusing file_clock = see below;
    […]
    
  2. Change 23.17.7.5 [time.clock.file] as indicated:

    23.17.7.5 ClassType file_clock [time.clock.file]

  3. Change 23.17.7.5.1 [time.clock.file.overview], class file_clock synopsis, as indicated:

    namespace std::chrono {
      using file_clock = see below;
      class file_clock {
      public:
        using rep = a signed arithmetic type;
        using period = ratio<unspecified, unspecified>;
        using duration = chrono::duration<rep, period>;
        using time_point = chrono::time_point<file_clock>;
        static constexpr bool is_steady = unspecified;
        
        static time_point now() noexcept;
        
        // Conversion functions, see below
      };
    }
    

    -1- The clock file_clock is an alias for a type meeting the TrivialClock requirements (23.17.3 [time.clock.req]), which uses a signed arithmetic type for file_clock::rep. file_clock is used to create the time_point system used for file_time_type (30.11 [filesystems]). Its epoch is unspecified, and noexcept(file_clock::now()) is true. [Note: The type file_clock denotes may be in a different namespace than std::chrono, such as std::filesystem. — end note]

  4. Change 23.17.7.5.2 [time.clock.file.members] as indicated:

    static time_point now();
    

    -1- Returns: A file_clock::time_point indicating the current time.

    -2- The class file_clock shalltype denoted by file_clock provides precisely one of the following two sets of static member functions: […]

[2018-08-23 Batavia Issues processing: Minor wording changes, and status to "Tentatively Ready".]

Proposed resolution:

This wording is relative to N4762.

  1. Change 23.17.2 [time.syn], header <chrono> synopsis, as indicated:

    […]
    // 23.17.7.5 [time.clock.file], classtype file_clock
    classusing file_clock = see below;
    […]
    
  2. Change 23.17.7.5 [time.clock.file] as indicated:

    23.17.7.5 ClassType file_clock [time.clock.file]

  3. Change 23.17.7.5.1 [time.clock.file.overview], class file_clock synopsis, as indicated:

    namespace std::chrono {
      using file_clock = see below;
      class file_clock {
      public:
        using rep = a signed arithmetic type;
        using period = ratio<unspecified, unspecified>;
        using duration = chrono::duration<rep, period>;
        using time_point = chrono::time_point<file_clock>;
        static constexpr bool is_steady = unspecified;
        
        static time_point now() noexcept;
        
        // Conversion functions, see below
      };
    }
    

    -1- The clock file_clock is an alias for a type meeting the Cpp17TrivialClock requirements (23.17.3 [time.clock.req]), and using a signed arithmetic type for file_clock::rep. file_clock is used to create the time_point system used for file_time_type (30.11 [filesystems]). Its epoch is unspecified, and noexcept(file_clock::now()) is true. [Note: The type that file_clock denotes may be in a different namespace than std::chrono, such as std::filesystem. — end note]

  4. Change 23.17.7.5.2 [time.clock.file.members] as indicated:

    static time_point now();
    

    -1- Returns: A file_clock::time_point indicating the current time.

    -2- The type file_clock shalltype denoted by file_clock provides precisely one of the following two sets of static member functions: […]


3147(i). Definitions of "likely" and "unlikely" are likely to cause problems

Section: 20.5.4.3.2 [macro.names] Status: Tentatively Ready Submitter: Casey Carter Opened: 2018-08-01 Last modified: 2018-08-27

Priority: 0

View other active issues in [macro.names].

View all other issues in [macro.names].

View all issues with Tentatively Ready status.

Discussion:

20.5.4.3.2 [macro.names]/2 forbids a translation unit to define names "lexically identical to […] the attribute-tokens described in 10.6 [dcl.attr]." We recently added the attribute-tokens likely and unlikely (10.6.7 [dcl.attr.likelihood]). These names are in extremely wide use as function-like macros in the open source community, forbidding users to define them breaks large amounts of code. (Reportedly Chromium contains 19 definitions each of "likely" and "unlikely" as function-like macros.)

Indeed, this issue came up during EWG discussion of P0479R1 "Attributes for Likely and Unlikely Statements" in Kona, and EWG decided to keep the names "likely" and "unlikely" for the attribute tokens since the usage wouldn't conflict with defining them as function-like macros. 20.5.4.3.2 [macro.names]/2 should not break large amounts of existing code that doesn't actually conflict with the use of the [[likely]] and [[unlikely]] attributes.

[2018-08-20 Status to Tentatively Ready after five positive votes on the reflector.]

Proposed resolution:

This wording is relative to N4762.

  1. Change 20.5.4.3.2 [macro.names] as indicated:

    [Drafting Note: If both this proposed resolution and the proposed resolution of LWG 3132 are accepted, the text inserted by LWG 3132 should precede the text added here.]

    -2- A translation unit shall not #define or #undef names lexically identical to keywords, to the identifiers listed in Table 4, or to the attribute-tokens described in 10.6 [dcl.attr], except that the names likely and unlikely may be defined as function-like macros (19.3 [cpp.replace]).


3148(i). <concepts> should be freestanding

Section: 20.5.1.3 [compliance] Status: Tentatively Ready Submitter: Casey Carter Opened: 2018-08-09 Last modified: 2018-08-27

Priority: 0

View all other issues in [compliance].

View all issues with Tentatively Ready status.

Discussion:

The design intent of the <concepts> header is that it contains only fundamental concept definitions and implementations of customization points that are used by those concept definitions. There should never be components in the header that require operating system support. Consequently, freestanding implementations can and should provide it. It is an oversight on the part of LWG - and in particular the author of P0898R3 "Standard Libary Concepts" - that the <concepts> header is not required to be provided by freestanding implementations.

[2018-08 Batavia Monday issue prioritization]

Priority set to 0, status to 'Tentatively Ready'

Proposed resolution:

This wording is relative to N4762.

  1. In 20.5.1.3 [compliance], add a new row to Table 21:

    Table 21 — C++ headers for freestanding implementations
    SubclauseHeader(s)
    […] […] […]
    21.12 [support.runtime] Other runtime support <cstdarg>
    [concepts] Concepts library <concepts>
    23.15 [meta] Type traits <type_traits>
    […] […] […]

3153(i). Common and common_type have too little in common

Section: 99 [concept.common] Status: Tentatively Ready Submitter: Casey Carter Opened: 2018-08-10 Last modified: 2018-08-27

Priority: 0

View other active issues in [concept.common].

View all other issues in [concept.common].

View all issues with Tentatively Ready status.

Discussion:

The Common concept when applied to types T and U requires that T and U are each ConvertibleTo (99 [concept.convertibleto]) their common type common_type_t<T, U>. ConvertibleTo requires both implicit and explicit conversions with equivalent results. The requirement for implicit conversion is notably not a requirement for specializing common_type as detailed in 23.15.7.6 [meta.trans.other]:

-5- Such a specialization need not have a member named type, but if it does, that member shall be a typedef-name for an accessible and unambiguous cv-unqualified non-reference type C to which each of the types T1 and T2 is explicitly convertible.

which only requires explicit conversion to be valid. While it's not inconsistent that the Common concept's requirements are a refinement of the requirements for common_type, there's no good reason for this additional requirement. The stated design intent is to enable writing monomorphic predicates that can compare Ts with Us (and vice versa) by accepting two arguments of type common_type_t<T, U>, but this role has been superseded by the addition of CommonReference and common_reference_t to the ranges design. The existence of pairs of types that are only explicitly convertible to their common type suggests that using Common in this way would never be a fully generic solution in any case.

The only existing use of the Common concept in either the working draft or the Ranges proposal is as a soundness check on the comparison and difference operators of counted_iterator, none of which actually convert any argument to the common type in their normal operation. It would seem that we could strike the additional requirement without impacting the Ranges design, which would allow for future uses of the Common concept with types like chrono::duration (23.17.5 [time.duration]) which sometimes provide only explicit conversion to a common type.

Notably, removing the requirement for implicit conversion will also make the Common concept consistent with the description in 99 [concept.common] p1: "If T and U can both be explicitly converted to some third type, C, then T and U share a common type, C."

[2018-08 Batavia Monday issue prioritization]

P0; Status to 'Tentatively Ready' after adding two semicolons to the P/R.

Proposed resolution:

This wording is relative to N4762.


3154(i). Common and CommonReference have a common defect

Section: 99 [concept.common] Status: Tentatively Ready Submitter: Casey Carter Opened: 2018-08-10 Last modified: 2018-08-27

Priority: 0

View other active issues in [concept.common].

View all other issues in [concept.common].

View all issues with Tentatively Ready status.

Discussion:

The semantic requirements of both Common (99 [concept.common]):

-2- Let C be common_­type_­t<T, U>. Let t be a function whose return type is T, and let u be a function whose return type is U. Common<T, U> is satisfied only if:

(2.1) — C(t()) equals C(t()) if and only if t() is an equality-preserving expression ( [concepts.equality]).

(2.2) — C(u()) equals C(u()) if and only if u() is an equality-preserving expression ( [concepts.equality]).

and similarly CommonReference ( [concept.commonreference]):

-2- Let C be common_­reference_­t<T, U>. Let t be a function whose return type is T, and let u be a function whose return type is U. CommonReference<T, U> is satisfied only if:

(2.1) — C(t()) equals C(t()) if and only if t() is an equality-preserving expression ( [concepts.equality]).

(2.2) — C(u()) equals C(u()) if and only if u() is an equality-preserving expression.

don't properly reflect the intended design that conversions to the common type / common reference type are identity-preserving: in other words, that converting two values to the common type produces equal results if and only if the values were initially equal. The phrasing "C(E) equals C(E) if and only if E is an equality-preserving expression" is also clearly defective regardless of the intended design: the assertion "E is not equality-preserving" does not imply that every evaluation of E produces different results.

[2018-08 Batavia Monday issue prioritization]

Priority set to 0, status to 'Tentatively Ready'

Proposed resolution:

This wording is relative to N4762.


3160(i). atomic_ref() = delete; should be deleted

Section: 32.6 [atomics.ref.generic] Status: Tentatively Ready Submitter: Tim Song Opened: 2018-10-01 Last modified: 2018-10-07

Priority: 0

View all issues with Tentatively Ready status.

Discussion:

atomic_ref has a deleted default constructor, which causes pointless ambiguities in cases like:

void meow(atomic_ref<int>);
void meow(some_default_constructible_struct);

meow({});

It should have no default constructor rather than a deleted one. (Note that it has other user-defined constructors and so cannot be an aggregate under any definition.)

[2018-10-06 Status to Tentatively Ready after seven positive votes on the reflector.]

Proposed resolution:

This wording is relative to N4762.