2017-06-05 61 views
12

Wydaje mi się, że istnieje niezgodność w standardzie C++, w szczególności w § 30.7.5.2.4 szkicu C++ 17 (N4659), o tym, kiedy znaki są rozszerzone w sformatowanych operacjach wyjściowych na wyjściowych strumieniach (operator<<()). Dokładnie ta sama niespójność wydaje się być odzwierciedlona w en.cppreference.com.C++ Kiedy znaki są rozszerzone w operatorze strumienia wyjściowego <<()?

pierwsze, przyjęto następujące deklaracje:

std::ostream out; 
std::wostream wout; 
char ch; 
wchar_t wch; 
const char* str; 
const wchar_t* wstr; 

Następnie stwierdził, że

  1. out << chnie wykonać charakter rozszerzający,
  2. out << str wykonuje znak poszerzenie,
  3. wout << ch wykonuje charakter szeroki ning,
  4. wout << str wykonuje znak poszerzenie,
  5. wout << wchnie wykonać charakter rozszerzający,
  6. wout << wstr wykonuje znak poszerza.

Pierwszy i oczywiste jest, że niezgodność (6) nie może być prawdziwe, ponieważ nie ma widen() funkcja podejmowania wchar_t argumentu tylko jeden, który wymaga char argumentu.

Druga (pozorna) niespójność jest pomiędzy (1) i (2). Wydaje mi się dziwne, że out << "x" powinien poszerzyć się o 'x', podczas gdy out << 'x' nie powinien.

Czy źle interpretuję standardowy tekst, czy coś tam jest nie tak? Jeśli to drugie jest prawdziwe, czy wiesz, jakie jest zamierzone zachowanie?

EDYCJA: Wydaje się, że ta niespójność (jeśli mam rację), była obecna w standardzie od co najmniej C++ 03 (§27.6.2.5.4). Tekst zmienia się nieco poprzez standardy pośrednie, ale niespójność, jak to wyjaśnię powyżej, pozostaje.

+2

To powinien być problem z LWG. –

+0

"... Jeśli c ma typ char, a typ znaku nie jest char, to seq składa się z out.widen (c), w przeciwnym razie seq składa się z c. ..." Sorry, my English (and understanding ogólnie, dlaczego nie) nie jest tak dobry; Czy możesz wskazać jedno ze zdań, w którym znajdziesz niespójności? – Loreto

+0

@Loreto Niespójność nie jest tak naprawdę w jednym zdaniu standardu. Jak opisałem powyżej, (1) i (2) sem są ze sobą w konflikcie, a Dietmar potwierdza, że ​​(1) jest poprawne, i (2) jest błędne (niewłaściwie podąża za błędnym sformułowaniem). –

Odpowiedz

5

Wygląda na to, że standard nie jest całkowicie poprawny. Większość problemu wynika ze specyfikacji zbiorczej odpowiednich operacji. Zamiast obsługi każdego przeciążenia poszczególne podobne przeciążenia są opisane razem, co prowadzi do wprowadzenia w błąd specyfikacji.

Wątpię, aby każdy wdrażający miał jakiekolwiek problemy ze zrozumieniem, co jest zamierzone. Zasadniczo, gdy char jest wstawiony do strumienia innego niż char, postać musi być widen() ed, aby uzyskać charakter typu znaku strumienia. To poszerzenie ma na celu odwzorowanie jednego znaku z zestawu znaków źródłowych na jeden znak w szerokim zestawie znaków strumienia.

Należy zauważyć, że specyfikacja IOStream zakłada pierwotne pojęcie znaków w strumieniach będących pojedynczymi elementami. Ponieważ specyfikacja została utworzona (dla wersji C++ 1998) tekst nie był tak naprawdę aktualizacją, ale z szerokim wykorzystaniem Unicode, "znaki" w strumieniu są naprawdę bajtami kodowania. Chociaż strumienie w większości działają poprawnie w tym zmodyfikowanym środowisku, pewna elastyczność, która byłaby przydatna w obsłudze znaków Unicode, nie jest właściwie obsługiwana.Brak czegoś "poszerzenia" jednego znaku w sekwencji bajtów UTF8 jest prawdopodobnie jednym z nich.

Jeśli uważasz, że niespójność/niepoprawność w sekcji strumienia nakazuje adresowanie, zgłoś zgłoszenie usterki. Instrukcja składania raportów o błędach znajduje się pod numerem http://isocpp.org. Gdy zgłosisz problem, rozważ proponowanie sformułowania, aby rozwiązać problem. Ponieważ nie ma jasności co do tego, co jest zamierzone i prawdopodobnie większość implementacji zrobi to, co należy, oczekuję, że kwestia ta uzyska dość niski priorytet i bez proponowanego sformułowania raczej nie będzie zwracać na nią większej uwagi. Oczywiście, rozwiązanie problemu nie zmieni zamierzonego zachowania, np. "Poszerzenia" char s na sekwencję UTF8: to faktycznie byłoby przeprojektowanie biblioteki strumieni, która może być w porządku, ale nie będzie wykonana jako część rozdzielczości defektu.

+0

Istnieje wiele okazji, w których standard określa bezwarunkowe wywołania 'poszerzania', bez żadnego wskazania, że ​​może on zostać pominięty dla przypadków tego samego typu. –

+0

@ T.C .: na pewno. Jeśli uważasz, że jest to coś, co należy naprawić, podnieś wadę. Jeśli specyfikacja zakończy się nakazem wywoływania 'rozszerzen()' we wszystkich przypadkach będzie to miało czysty efekt, że na szczęście wszyscy implementatorzy powinni zdać sobie sprawę, że wynik 'poszerz()' musi być buforowany, więc funkcja 'wirtualna' jest wywoływana tylko raz . –

+1

W istocie - myślę, że można bezpiecznie powiedzieć, że komisja prawdopodobnie wyglądałaby pozytywnie przynajmniej z myślą o całkowitym remoncie projektów - z zastrzeżeniem, że jest to * niezwykle * nietrywialne przedsięwzięcie, więc każda taka propozycja zostanie poddana do wielu analiz i istnieje wiele niepisanych, słabo znanych i najprawdopodobniej sprzecznych celów, które musiałby spełnić, aby mieć nadzieję na sukces. –