basic_syncbuf
-related manipulators refer to some Allocator
without defining itSection: 31.7.6.5 [ostream.manip] Status: New Submitter: Jonathan Wakely Opened: 2020-11-15 Last modified: 2020-11-21
Priority: 3
View all other issues in [ostream.manip].
View all issues with New status.
Discussion:
From this editorial issue request:
The three basic_syncbuf
-related manipulators emit_on_flush
, noemit_on_flush
,
and flush_emit
use in their Effects: elements the following wording:
"If
os.rdbuf()
is abasic_syncbuf<charT, traits, Allocator>*
, calledbuf
for the purpose of exposition, calls […]
There are two problems with that wording (even when considering the helpful note following p8): First,
the type Allocator
is not defined elsewhere (e.g. it is not part of the function signature)
and second, os.rdbuf()
has type basic_streambuf<charT, traits>*
and not any
other type.
SYNCBUF
to detect basic_syncbuf
during the work
on the above mentioned editorial issue to solve these problems it turned out that the suggested wording
fix would introduce an apparently normative change that the syncbuf
type must not use a
program-defined specialization.
[2020-11-21; Reflector prioritization]
Set priority to 3 during reflector discussions.
Proposed resolution:
This wording is relative to N4868.
This proposed wording is known to be incorrect, but is nonetheless depicted to present the overall idea.
Modify 31.7.6.5 [ostream.manip] as indicated:
-1- Each instantiation of any of the function templates specified in this subclause is a designated addressable function (16.4.5.2.1 [namespace.std]).
-?- In this subclause,SYNCBUF(p)
for a pointerp
of typeB*
is determined as follows. If*p
is a base class subobject of an object of typeS
, whereS
is a specialization generated from thebasic_syncbuf
primary template, andis_convertible_v<S*, B*>
istrue
, thenSYNCBUF(p)
isdynamic_cast<S*>(p)
. Otherwise,SYNCBUF(p)
isstatic_cast<void*>(nullptr)
. [Note ?: To work around the issue that theAllocator
template argument ofS
cannot be deduced, implementations can introduce an intermediate base class tobasic_syncbuf
that manages itsemit_on_sync
flag. — end note] […]template<class charT, class traits> basic_ostream<charT, traits>& emit_on_flush(basic_ostream<charT, traits>& os);Let
-8- Effects: Ifp
beSYNCBUF(os.rdbuf())
.p
is not nullos.rdbuf()a, callsbasic_syncbuf<charT, traits, Allocator>*
, calledbuf
for the purpose of expositionp
. Otherwise this manipulator has no effect.buf->set_emit_on_sync(true)[Note 1: To work around the issue that the Allocator template argument cannot be deduced, implementations can introduce an intermediate base class to-9- Returns:basic_syncbuf
that manages itsemit_on_sync
flag. — end note]os
.template<class charT, class traits> basic_ostream<charT, traits>& noemit_on_flush(basic_ostream<charT, traits>& os);Let
-10- Effects: Ifp
beSYNCBUF(os.rdbuf())
.p
is not nullos.rdbuf()a, callsbasic_syncbuf<charT, traits, Allocator>*
, calledbuf
for the purpose of expositionp
. Otherwise this manipulator has no effect. -11- Returns:buf->set_emit_on_sync(false)os
.template<class charT, class traits> basic_ostream<charT, traits>& flush_emit(basic_ostream<charT, traits>& os);Let
-12- Effects: Callsp
beSYNCBUF(os.rdbuf())
.os.flush()
. Then, ifp
is not nullos.rdbuf()a, callsbasic_syncbuf<charT, traits, Allocator>*
, calledbuf
for the purpose of expositionp
. -13- Returns:buf->emit()os
.