3399. basic_syncbuf::emit() + Qt's #define emit = Big Bada-Boom

Section: 31.11.2.1 [syncstream.syncbuf.overview] Status: NAD Submitter: Marc Mutz Opened: 2019-02-14 Last modified: 2020-11-09

Priority: Not Prioritized

View all other issues in [syncstream.syncbuf.overview].

View all issues with NAD status.

Discussion:

The current IS contains a function called emit() (in basic_syncbuf, added by P0053).

emit is a macro in pervasive use in every Qt program. #include'ing <osyncstream> after any Qt header would break, because emit was #define'd to nothing by the Qt headers.

It is understood that the committee cannot check every 3rd-party library out there that chooses (badly, as I’d readily concur) to #define a macro of all-lowercase letters, but the min/max issue in the Windows headers caused so much pain for our users, that we probably should avoid a breakage here, for the benefit of our users that have to work Qt.

It also doesn’t seem like emit() is a particularly mandatory name for the syncbuf function. Since it returns bool, it could just as easily be called try_emit() and the issue would be solved.

Suggested approach:

In basic_syncbuf, rename bool emit() to bool try_emit(). In basic_osyncstream, where the function doesn't return bool, but sets the stream's failbit, rename void emit() to void emit_or_fail().

[2020-02-14, Prague]

The issue was send to LEWG, who made the following poll:

We're open to renaming osyncstream::emit() (and related).

SF F N A SA
1  1 5 8 20

[2020-11-09 Status changed: Tentatively NAD → NAD.]

Proposed resolution:

This wording is relative to N4849.

  1. Modify 31.7.6.5 [ostream.manip] as indicated:

    template<class charT, class traits>
      basic_ostream<charT, traits>& flush_emit(basic_ostream<charT, traits>& os);
    

    -12- Effects: Calls os.flush(). Then, if os.rdbuf() is a basic_syncbuf<charT, traits, Allocator>*, called buf for the purpose of exposition, calls buf->try_emit().

  2. Modify 31.11.2.1 [syncstream.syncbuf.overview] as indicated:

    […]
    // 31.11.2.4 [syncstream.syncbuf.members], member functions
    bool try_emit();
    streambuf_type* get_wrapped() const noexcept;
    […]
    

    -1- Class template basic_syncbuf stores character data written to it, known as the associated output, into internal buffers allocated using the object's allocator. The associated output is transferred to the wrapped stream buffer object *wrapped when try_emit() is called or when the basic_syncbuf object is destroyed. Such transfers are atomic with respect to transfers by other basic_syncbuf objects with the same wrapped stream buffer object.

  3. Modify 31.11.2.2 [syncstream.syncbuf.cons] as indicated:

    ~basic_syncbuf();
    

    -7- Effects: Calls try_emit().

    -8- Throws: Nothing. If an exception is thrown from try_emit(), the destructor catches and ignores that exception.

  4. Modify 31.11.2.3 [syncstream.syncbuf.assign] as indicated:

    basic_syncbuf& operator=(basic_syncbuf&& rhs) noexcept;
    

    -1- Effects: Calls try_emit() then move assigns from rhs. After the move assignment *this has the observable state it would have had if it had been move constructed from rhs (31.11.2.2 [syncstream.syncbuf.cons]).

  5. Replace in 31.11.2.4 [syncstream.syncbuf.members] all occurrences of emit() by try_emit() (five occurrences)

  6. Replace in 31.11.2.5 [syncstream.syncbuf.virtuals] all occurrences of emit() by try_emit() (three occurrences)

  7. Modify 31.11.3.1 [syncstream.osyncstream.overview] as indicated:

    […]
    // 31.11.3.3 [syncstream.osyncstream.members], member functions
    void emit_or_fail();
    streambuf_type* get_wrapped() const noexcept;
    […]
    
  8. Replace in 31.11.3.2 [syncstream.osyncstream.cons] all occurrences of emit() by emit_or_fail() (three occurrences)

  9. Replace in [syncstream.osyncstream.assign] all occurrences of emit() by emit_or_fail() (two occurrences)

  10. Replace in 31.11.3.3 [syncstream.osyncstream.members] all occurrences of emit() by emit_or_fail() (six occurrences)