2015-06-06 9 views
7

Der Titel ist relativ selbsterklärend. Ich erkenne die Ähnlichkeit mit anderen Antworten, aber alle haben unterschiedliche Anordnungen von Operatoren (und daher unterschiedliche Regeln für das Casting). Daher benötige ich eine Antwort, die diesen speziellen Fall verdeutlicht.Ist std :: string :: npos == -1 immer wahr?

Wenn jemand auf den Abschnitt des Standards hinweisen könnte, der das erklärt, werde ich gerne die Stimme abgeben und die Antwort akzeptieren.

Antwort

7

NO, es ist nicht immer wahr. Es ist jedoch ein wenig komplizierter, als es auf den ersten Blick scheint:

Am Anfang, lassen Sie uns sehen, was std::string ist (21,3/1):

Der Header <string> definiert die basic_string Klassenvorlage für die Manipulation variierende Längensequenzen von kohleartigen Objekten und vier typedefs, string, u16string, u32string und wstring, dass die Namen Spezialisierungen basic_string<char>, basic_string<char16_t>, basic_string<char32_t> und basic_string<wchar_t>, JEWEILIGEN ely.

beginnen mit 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] 
}; 

Beachten Sie, dass während npos mit -1 initialisiert wird, seine Art auf Allocator::size_type abhängt, was bedeutet, dass ohne weiteres Wissen, können wir nicht einfach davon ausgehen, dass string::npos == -1 wird sogar kompilieren.

Jetzt, da string das Standard-Allocator verwendet (die Template-Parameter den Standardwert in der typedef von der Standardbibliothek zur Verfügung gestellt, nachdem alle haben), lassen Sie uns 20.6.9 überprüfen:

typedef size_t size_type; 

Nun können wir die Frage im Wesentlichen wie folgt umschreiben: size_t(-1) == -1. Was nun passiert, hängt von den Typen der Teilausdrücke ab: Die linke Seite hat offensichtlich den Typ size_t, während die rechte Seite ein ganzzahliges Literal ist, das den Typ int hat, wenn es so geschrieben wird (ohne weitere Qualifier).

Das Ergebnis ist truesize_t wenn die mindestens so groß ist wie int (Normen Fanatiker: hat einen größeren Ganzzahl-Umwandlungs Rang wie in 4.13 definiert). Andernfalls wird die linke Seite zu int befördert zu werden, wie ein Vergleich 0xFFFF == -1 verursacht (für size_tuint16_t und int wobei 32 Bit aufweist), die false ist.

Beachten Sie, dass 16-Bit-Systeme selbst nicht mehr sehr häufig sind (abgesehen von einigen Überresten in sehr kleinen Formfaktoren), int ist nicht auf 32-Bit vom Standard beschränkt. Ein Compiler, der x86_64 mit 64 Bit size_t und 128 Bit int anvisiert, wäre technisch kompatibel.

Alle Zitate stammen aus dem C++ 11 Standard (ISO/IEC 14882: 2011).

+0

Als eine Folgefrage würde zuerst die Umwandlung des Typs der linken in einen vorzeichenbehafteten Typ bewirken, dass der Ausdruck garantiert wird? Zum Beispiel: '(signed size_t) std :: string :: npos == -1' – randomusername

+0

@randomusername Diese Konvertierung führt zu undefiniertem Verhalten, da der Wert von 'npos' zu groß ist. Mach einfach folgendes: 'std :: string :: npos == std :: string :: size_type (-1)' und alles geht gut. –

2

Ja ist definiert als -1

N4296 § 21.4/5 die Klassenvorlage für std::basic_string bereitstellt, die die Linie, die Sie buchstäblich fragte

static const size_type npos = -1; 
5

Es gibt eine Lücke für die Frage enthält.

Wenn int hat (streng) größer integer Umwandlung Rang als string::size_type und int kann das gesamte Spektrum des Wertes von string::size_type speichert, dann wird string::npos == -1 falsch sein, da beiden Argumente zu int befördert zu werden, anstatt zu string::size_type gefördert.

Eine Umgebung, in der dies geschieht, wäre eher ungewöhnlich.

Dies kommt von den üblichen arithmetischen Umwandlungen:

...

Andernfalls, wenn der Operand, unsigned integer Typen hat hat Rang größer oder gleich den Rang des Typs des anderen Operanden wird der Operand mit vorzeichenbehafteten Integer-Typ in konvertiert. Der Typ des Operanden mit vorzeichenloser Integer-Zahl

Sonst, wenn der Typ der Ope rand mit vorzeichenbehafteten Integer-Typ kann alle Werte von den Typ des Operanden mit vorzeichenlosen Integer-Typ darstellen, der Operand mit vorzeichenlosen Integer-Typ soll in den Typ des Operanden mit vorzeichenbehafteten Integer-Typ konvertiert werden .

Andernfalls müssen beide Operanden in den vorzeichenlosen ganzzahligen Typ konvertiert werden, der dem Typ des Operanden mit vorzeichenbehafteten Integer-Typ entspricht.

+0

Also schlagen Sie vor, dass 'string :: size_type' in der Besetzung nicht auf" int "erweitert wurde? – randomusername

+0

@randomusername: 'string :: size_type' ist vorzeichenlos, daher gibt es kein zu erweiterndes Vorzeichen; Die Konvertierung behält den Wert bei und wird daher in ein nicht negatives "int" umgewandelt. Beachten Sie, dass 'npos' ein positiver Wert ist: tatsächlich der größte Wert, der in' string :: size_type' gespeichert werden kann. – Hurkyl