简体   繁体   中英

Is std::string::npos == -1 always true?

The title is relatively self explanatory. I recognize the similarity to other answers, but all of those have different arrangements of operators (and therefore different casting rules). So I require an answer that clarifies this particular case.

If someone could point out the section of the standard that explains this, I will gladly vote up and accept the answer.

NO , it is not always true. It is however a bit more complicated than it seems at first glance:

In the beginning, let us see what std::string is (21.3/1):

The header <string> defines the basic_string class template for manipulating varying-length sequences of char-like objects and four typedefs, string , u16string , u32string , and wstring , that name the specializations basic_string<char> , basic_string<char16_t> , basic_string<char32_t> , and basic_string<wchar_t> , respectively.

Start out with 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] }; 

Note that while npos is initialized with -1 , its type depends on Allocator::size_type , which means that without further knowledge, we cannot simply assume that string::npos == -1 will even compile.

Now, as string uses the default allocator (the template parameter has the default value in the typedef provided by the standard library after all), let us check 20.6.9:

 typedef size_t size_type; 

Now, we can essentially rewrite the question as: size_t(-1) == -1 . What happens now depends on the types of the subexpressions: The left hand side obviously has type size_t , while the right hand side is an integer literal, which has type int , when written like this (without further qualifiers).

The result is true if size_t is at least as large as int (for standards fanatics: Has a larger integer conversion rank as defined in 4.13). Otherwise, the left hand side will get promoted to int , causing a comparision like 0xFFFF == -1 (for size_t being uint16_t and int having 32 bit), which is false .

Note that while 16 bit systems themselves are not very common anymore (except for some remnants in very small form factors), int is not restricted to 32 bit by the standard. A compiler targetting x86_64 with 64 bit size_t and 128 bit int would be technically compliant.

All quotes are from the C++11 standard (ISO/IEC 14882:2011).

There is a loophole for the question you literally asked.

If int has (strictly) greater integer conversion rank than string::size_type and int can store the full range of values of string::size_type , then string::npos == -1 will be false, as both arguments will get promoted to int , rather than being promoted to string::size_type .

An environment where this happens would be rather unusual.

This comes from the usual arithmetic conversions :

...

Otherwise, if the operand that has unsigned integer type has rank greater than or equal to the rank of the type of the other operand, the operand with signed integer type shall be converted to the type of the operand with unsigned integer type

Otherwise, if the type of the operand with signed integer type can represent all of the values of the type of the operand with unsigned integer type, the operand with unsigned integer type shall be converted to the type of the operand with signed integer type.

Otherwise, both operands shall be converted to the unsigned integer type corresponding to the type of the operand with signed integer type.

Yes, it is defined as -1

N4296 § 21.4 / 5 provides the class template for std::basic_string which includes the line

static const size_type npos = -1;

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM