2015-06-06 14 views
7

Il titolo è relativamente auto esplicativo. Riconosco la somiglianza con altre risposte, ma tutte hanno disposizioni diverse di operatori (e quindi regole di casting diverse). Quindi ho bisogno di una risposta che chiarisca questo caso particolare.È std :: string :: npos == -1 sempre vero?

Se qualcuno potrebbe indicare la sezione dello standard che spiega ciò, voterò volentieri e accetto la risposta.

risposta

7

NO, non è sempre vero. E 'comunque un po' più complicato di quanto possa sembrare a prima vista:

In principio, vediamo che cosa std::string è (21,3/1):

L'intestazione <string> definisce il modello basic_string classe per la manipolazione sequenze variando lunghezza di oggetti char-like e quattro typedef, string, u16string, u32string e wstring, che nome specializzazioni basic_string<char>, basic_string<char16_t>, basic_string<char32_t> e basic_string<wchar_t>, respectiv ely.

iniziare con 21,4/5:

template<class charT, class traits = char_traits<charT>, 
    class Allocator = allocator<charT> > 
class basic_string { 
    typedef typename allocator_traits<Allocator>::size_type size_type; 
    static const size_type npos = -1; 
// [other members omitted] 
}; 

nota che mentre npos inizializzato con -1, il suo tipo dipende Allocator::size_type, il che significa che senza ulteriori conoscenze, non possiamo semplicemente presumere che string::npos == -1 sarà anche compilato.

Ora, come string utilizza l'allocatore di default (il parametro di modello ha il valore di default nella typedef fornito dalla libreria standard, dopo tutto), cerchiamo di controllare 20.6.9:

typedef size_t size_type; 

Ora, possiamo essenzialmente riscrivere la domanda come: size_t(-1) == -1. Quello che succede ora dipende dal tipo delle sottoespressioni: Il lato sinistro ha ovviamente il tipo size_t, mentre il lato destro è un valore letterale intero, che ha il tipo int, se scritto in questo modo (senza ulteriori qualificazioni).

Il risultato è true se size_t è almeno grande quanto int (per gli standard fanatici: ha una più grande grado di conversione intero come definito nella 4.13). In caso contrario, il lato sinistra otterrà promosso int, causando un confronto come 0xFFFF == -1 (per size_t essere uint16_t e int avente 32 bit), che è false.

Si noti che mentre i sistemi a 16 bit stessi non sono più molto comuni (ad eccezione di alcuni residui in fattori di forma molto piccoli), int non è limitato a 32 bit dallo standard. Un compilatore che punta su x86_64 con bit size_t e 128 bit int sarebbe tecnicamente conforme.

Tutte le virgolette sono dello standard C++ 11 (ISO/IEC 14882: 2011).

+0

Come domanda di follow-up, prima convertendo il tipo di lato sinistro in un tipo firmato, si garantisce l'espressione? Ad esempio: '(signed size_t) std :: string :: npos == -1' – randomusername

+0

@randomusername Questa conversione ha come risultato un comportamento indefinito, poiché il valore di' npos' è troppo grande. Basta fare quanto segue: 'std :: string :: npos == std :: string :: size_type (-1)' e stai bene. –

2

Sì, essa è definita come -1

N4296 § 21.4/5 fornisce il modello di classe per std::basic_string che comprende la linea

static const size_type npos = -1; 
5

C'è una scappatoia per la domanda che hai chiesto alla lettera.

Se int ha (strettamente) superiore rango di conversione interi di string::size_type e int in grado di memorizzare l'intera gamma di valori di string::size_type, quindi string::npos == -1 sarà falsa, in quanto entrambi gli argomenti avranno promosso a int, invece di essere promosso a string::size_type.

Un ambiente in cui ciò si verifica sarebbe piuttosto insolito.

Questo deriva dalla conversioni aritmetiche abituali:

...

Altrimenti, se l'operando che ha senza segno tipo intero ha rango superiore o uguale al rango del tipo dell'altro operando, l'operando con tipo intero con segno deve essere convertito in il tipo di operando con tipo intero senza segno

Altrimenti, se il tipo di ope rand con tipo intero con segno può rappresentare tutti i valori di il tipo di operando con tipo intero senza segno, l'operando con tipo intero senza segno deve essere convertito nel tipo di operando con tipo intero con segno.

In caso contrario, entrambi gli operandi devono essere convertiti nel tipo intero senza segno corrispondente al tipo dell'operando con tipo intero con segno.

+0

Quindi stai suggerendo che 'string :: size_type' non verrebbe esteso nel cast a' int'? – randomusername

+0

@randomusername: 'string :: size_type' non è firmato, quindi non vi è alcun segno da estendere; la conversione conserva il valore e quindi verrà convertito in un 'int' non negativo. Si noti che 'npos' è un valore positivo: infatti, il valore più grande che può essere memorizzato in' string :: size_type'. – Hurkyl