2013-08-20 19 views
7

Sto imparando C++ 11 e sono interessato ai valori letterali definiti dall'utente. Quindi ho deciso di giocare un po 'con esso. Alcune lingue hanno una sintassi simile a questo:C++ 11 letterali definiti dall'utente

int n = 1000_000_000; 

ho cercato di simulare questa funzione in C++ 11.

inline constexpr unsigned long long operator "" _000 (unsigned long long n)noexcept 
{ 
     return n * 1000; 
} 

inline constexpr unsigned long long operator "" _000_000 (unsigned long long n)noexcept 
{ 
     return n * 1000*1000; 
} 

inline constexpr unsigned long long operator "" _000_000_000 (unsigned long long n)noexcept 
{ 
     return n * 1000*1000*1000; 
} 

int main(){ 
    constexpr auto i = 100_000; // instead of 100000 
    constexpr auto j = 23_000_000; // instead of 23000000; 
} 

Ma per il caso generale non ho potuto simulare, vale a dire

auto general_case = 123_456_789; // non può compilare

La mia domanda è "Posso simulare per il caso generale come sopra usando C++ 11?".

+2

Funziona per 1_000_000? Personalmente userò letterali utente personalizzati e le lettere K M G (kilo mega giga). – dtech

+0

1_000_000 compilato !!! –

+0

@driver solo problema con quello è quindi non si può essere così esatti – aaronman

risposta

4

Questo non è possibile con i letterali definiti dall'utente nella versione C++ 11 della lingua come è adesso. I letterali definiti dall'utente supportano un formato limitato per i parametri, non sembra supportare un parametro sul lato destro, il concatenamento, in più vi è il problema di rappresentare numeri che iniziano con 0 come numeri reali. Quindi è un no.

L'approccio corrente definisce _000 e così via come valori letterali autonomi, quindi il compilatore funziona solo con loro e nessun altro. Non è come lo _ è l'operatore e lo 000 è un parametro con cui puoi lavorare purtroppo.

È tuttavia possibile utilizzare invece i suffissi delle lettere.

long long constexpr operator"" K (long double n) { 
    return n * 1000; 
} 
long long constexpr operator"" M (long double n) { 
    return n * 1000000; 
} 
long long constexpr operator"" G (long double n) { 
    return n * 1000000000; 
} 

E poi:

0.05M == 50000; 
123.232K == 123232 
1.000000001G == 1000000001 

Sicuramente, l'ultimo caso sorta di sconfigge lo scopo, perché ancora una volta si hanno molti zeri senza indicazione visiva ... Così si può andare per qualcosa di simile:

1.G + 1 == 1000000001 // much clearer 1 billion + 1 

Questo lo rende un po 'brutto, dal momento che il letterale si aspetta un numero reale e non funzionerà con un numero intero a meno che non si definisca un valore letterale extra solo per l'uso con numeri interi. Quindi puoi semplicemente usare 1G invece.

Inoltre, questo approccio probabilmente produrrà avvertenze del compilatore, apparentemente il gruppo C++ vuole riservare tutti i suffissi che non sono preceduti da underscore per "usi futuri". Se vuoi eliminare gli avvisi, usa invece _K _M e _G.

MODIFICA: Ho rimosso la soluzione dell'elenco di inizializzazione, perché produce risultati non validi con numeri come 010, che vengono elaborati come ottali e rovinano i calcoli.

+0

Sì, hai risolto il problema se il problema riguardava molti zeri finali, ma non lo hai risolto nel caso generale (ad es. '123456789' ->' 123456.789K' -> '123.456789M' -> no clear beneficio) –

+0

@LightnessRacesinOrbit - Sono d'accordo che è praticamente inutile, tuttavia è ancora utile come esempio per l'OP, che ha chiaramente sbagliato letteralmente. In realtà avevo aspettative per il parametro RHS e concatenamento, sembra che i letterali nella loro forma attuale siano piuttosto rudimentali. – dtech