42

Podczas dzyń kompiluje następujący wiersz, g ++ 6.1 narzeka separator cyfr (patrz live example on Coliru):Czy separatory C++ 14-cyfrowe są dozwolone w zdefiniowanych przez użytkownika literałach?

auto time = 01'23s; 

Który kompilator, jeżeli istnieje, jest poprawna według standardu C++ 14 (N3796)?

W przeciwnym razie, pozwala na to, że separatory cyfrowe (§2.14.2) są tylko szczegółami implementacji w zdefiniowanych przez użytkownika literałach (§ 2.14.8) biblioteki <chrono> (§20.12.5.8)? IMHO powinno nie być, ponieważ te literały są zdefiniowane na parametrach unsigned long long.

Pamiętam Howarda Hinnanta używającego 10'000s jako przykład podczas jego CppCon 2016 talk "A <chrono> tutorial" (około 42 minut w jego wykładzie).


(Należy pamiętać, że nie zamierzają kod "1 minutę i 23 sekund", który jest prawidłowe tylko przez przypadek, ponieważ ósemkowa dosłownewynosi 64 + 16 + 3 == 83. w tym celu należy napisać

auto time = 1min + 23s; 

ale możliwa interpretacja nie jest mylące część pytania).

+1

Wygląda na błąd biblioteki i powinien zostać zgłoszony. Moje ograniczone eksperymenty sugerują, że 'libstdC++' definiuje niewłaściwy rodzaj operatora dosłownego, przyjmując szablonowe nie-typowe parametry 'szablon ' zamiast 'unsigned long long'. Ale to nie jest wymagane przez standard i robi to źle. Zostawili operatora 'operatora '(unsigned long long)', myślę, że to jest podstawowy problem. (Mają "operatora" (długie podwójne) ', zgodnie z wymaganiami) –

+1

Błąd został zgłoszony tutaj: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=69905 (Ktoś inny opublikował ten link , a następnie skasowałem ich komentarz, ale myślę, że jest to poprawny link!) –

+1

@Aaron McDaid: Usunąłem ten komentarz, dodając go w mojej własnej odpowiedzi (patrz poniżej). –

Odpowiedz

19

Jeśli spojrzeć na gramatyce, zdefiniowany przez użytkownika liczbą całkowitą, dosłowne może byćósemkowy-dosłownym UD sufiksu i ósemkowy-dosłownym definiowany jest albo 0 lub ósemkowy-dosłownym” opcjonalnie ósemkowej cyfr.

N4140 §2.14.8

użytkownika zdefiniowanej dosłownym:

  • zdefiniowany przez użytkownika jest liczbą całkowitą, dosłownym
  • [...]

zdefiniowany przez użytkownika-całkowita-literalna:

  • ósemkowy-dosłownym UD sufiksu
  • [...]

N4140 §2.14.2

ósemkowy-dosłowny:

  • 0
  • ósemkowy-dosłowny” opt ósemkowy-cyfrowy

Więc 01'23s jest całkowicie poprawny dosłowne.

5

WLOG do literałach przecinku:

[lex.ext]:

zdefiniowany przez użytkownika jest liczbą całkowitą, dosłownym:
        dziesiętny dosłownym UD sufiksu

[lex.icon]:

dziesiętny-dosłowny:
        niezerowe cyfry
        dziesiętny-dosłowny   opt   cyfra

tj. tak, separatory cyfr są dozwolone w UDL.

5

To wydaje się być błędem w implementacji GCC biblioteki <chrono>, jak zasugerował @Aaron McDaid. Jest (obecnie niepotwierdzone) raport o błędzie: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=69905

libstdC++ GCC realizuje dwa podpisy std::chrono_literals:

constexpr chrono::duration<long double> 
operator""s(long double __secs) 
{ return chrono::duration<long double>{__secs}; } 

template <char... _Digits> 
    constexpr chrono::seconds 
    operator""s() 
    { return __check_overflow<chrono::seconds, _Digits...>(); } 

Wersja szablonu dając błędu nie jest wymagane przez normy. Dodając

constexpr chrono::seconds 
operator""s(unsigned long long __secs) 
{ return chrono::seconds{__secs}; } 

do nagłówka <chrono> (mojej instalacji lokalnej) na dissappears błędach.

jednak realizatorzy biblioteki GCC mogły pominąć tę wersję na celu, dzięki czemu mogą one zapobiec niepożądanym unsigned do podpisanego nawrócenia, ponieważ sekundy są zdefiniowane jako

typedef duration<int64_t> seconds; 

Edit:

Jak ostatnio zauważył Jonathan Wakely w komentarzach do raportu o błędzie, , implementacja została wybrana zgodnie z projektem w połączeniu z open Library Working Group issue, ale nie została wykorzystana separator cyfr s pod uwagę.

+0

Problem polega na tym, że standard wymaga sprawdzania przepełnienia podczas kompilacji, ale użycie gotowego operatora dosłownego nie pozwala na to. –

+0

Nie rozumiem, czym jest "ugotowany" operator, @ T.C .. Czy masz na myśli to, że "proste" niepotrzebne przeciążenie długo nie jest w stanie wykonać tego sprawdzenia podczas kompilacji? I dlatego szablon jest wymagany? –

+0

@AaronMcDaid Prawidłowo. "ugotowany" = jeden przyjmujący "unsigned long long"; "raw" = taki, który przyjmuje postacie. –