Таким образом, сокращая ваш код до минимального примера, вы спрашиваете, почему это печатает 0
:
#include <iostream>
#include <string>
int main()
{
int a = -1;
std::string::size_type b = 3;
int c = a % b;
std::cout << c << '\n';
}
Основная операция, о которой идет речь, заключается в следующем:
a % b
В соответствии со стандартом,
5,6 Мультипликативные операторы [expr.mul]
Операнды * и / должны иметь арифметику c или тип перечисления с незаданной областью; операнды% должны иметь целочисленный или незаданный тип перечисления. Обычные арифметические c преобразования выполняются над операндами и определяют тип результата .
Так что насчёт этих "обычных арифметических * c конверсии "? Это должно соединить типы двух операндов с общим типом до для выполнения фактической операции. Далее рассматриваются в порядке :
- Если оба операнда являются целыми числами, целочисленное продвижение сначала выполняется для обоих операндов. Если после целочисленного преобразования операнды по-прежнему имеют разные типы, преобразование продолжается следующим образом:
- Если один операнд имеет тип без знака T, ранг преобразования которого по крайней мере так же высок, как у другого операнда, тогда другой операнд преобразуется в тип T.
- В противном случае один операнд имеет тип со знаком T, ранг преобразования которого выше, чем у типа другого операнда. Другой операнд преобразуется в тип T, только если тип T способен представлять все значения своего предыдущего типа.
- В противном случае оба операнда преобразуются в тип без знака, соответствующий типу со знаком T.
Это лот для легализации того, что фактически говорит это:
- У вас есть два операнда,
signed int
и std::string::size_type
- Ранг
std::string::size_type
на больше , чем signed int
- Следовательно, операнд
signed int
преобразуется в тип std::string:size_type
до до запрашиваемой операции.
Таким образом, все, что осталось, - это преобразование, то есть есть еще одна легализация:
4.7 Интегральные преобразования [conv.integral]
Если тип назначения не имеет знака, полученное значение является наименьшим целым числом без знака, совпадающим с целым числом источника (по модулю 2 n , где n - число битов, используемых для представления типа без знака). [Примечание: в представлении дополнения до двух это преобразование является концептуальным, и в битовой комбинации нет изменений (если нет усечения). - конец примечания]
Это означает, что на 32-битной std::string::size_type
платформе вы получите 2 32 -1 в качестве преобразованного значения из int
(-1).
Что означает ...
4294967295 % 3
Что означает ... ноль . Если std::string::size_type
64-битный, то все выше остается тем же, за исключением окончательного вычисления, которое будет:
18446744073709551615 % 3