Как C++ неявно приводит аргументы к компаратору, такому как ‹?

Я думал, что это будет легко решить вопрос через Google, но я не могу найти окончательный (или даже предположительный) ответ:

При использовании оператора сравнения, в каком порядке происходит неявное приведение типов?

int i = -1;
size_t t = 1;

bool result = i < t;

Является ли это эквивалентом:

bool result = i < int(t);    // equals true

or:

bool result = size_t(i) < t;    // equals false

Это легкая часть вопроса - вторая часть - "каково общее правило", каким оно может быть:

  1. Аргумент «более простой» всегда преобразуется в аргумент «более сложный» (т.е. size_t->int) или
  2. Первый (или второй) аргумент всегда преобразуется в тип второго (или первого) аргумента или
  3. Встроенные примитивы, такие как size_t и ints, имеют специальные операторы сравнения, которые определяют приведение в каждом конкретном случае.

Все три варианта кажутся разумными, хотя второй приводил бы к значительному поведению, отличающемуся от интуитивно ожидаемого большинством людей.

Компилятор VC++, похоже, считает, что при сравнении int с size_t следует выдавать предупреждение уровня 3, и все же он выдает предупреждение уровня 4 только тогда, когда вы возвращаете отрицательное число из функции, которая возвращает size_t (что приводит к числу, просто более половины максимального возвращаемого целого числа).

Пытаясь избавиться от всех предупреждений 4-го уровня, я теперь все равно явно привожу все, но я хотел знать «правду». Это должно быть определено где-то...


person Mike Sadler    schedule 30.01.2013    source источник
comment
Никоим образом не. Приведение по определению является явным. Неявное преобразование типов называется приведением.   -  person    schedule 30.01.2013
comment
Эти преобразования определены в разделе 4 стандарта C++.   -  person Gorpik    schedule 30.01.2013
comment
4 Стандартные преобразования: стр.77 и 4.5 Интегральные рекламные акции, стр.79 из open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3485.pdf   -  person qPCR4vir    schedule 30.01.2013
comment
Ах, отлично - я собирался спросить, где на самом деле был определен стандарт C++!   -  person Mike Sadler    schedule 31.01.2013


Ответы (2)


Правила довольно сложны и зависят от реализации. Однако в основном:

  1. Оба типа являются «раскрученными». Это означает, что все, что меньше int, повышается до int. (В маловероятном случае, когда size_t меньше, чем int, оно будет повышено до знакового int и потеряет свою беззнаковость.)

  2. Если один из типов может содержать все значения другого, другой преобразуется в этот тип.

  3. Если один из типов беззнаковый, а другой знаковый, и они имеют одинаковый размер, то знаковый преобразуется в беззнаковый.

Для int и size_t (которые должны быть без знака) это означает, что если size_t меньше int, int будет преобразовано в size_t.

person James Kanze    schedule 30.01.2013
comment
+1 см. также этот -n" rel="nofollow noreferrer">Эпизод 9 канала Стефана Т. Лававея - person TemplateRex; 30.01.2013
comment
Спасибо, @JamesKanze. Так что это, вероятно, то, что большинство людей ожидает / хочет - это хорошо. Я предполагаю, что существует теоретический риск, если беззнаковое целое число, превышающее половину его максимального размера, будет преобразовано в целое число со знаком, бит, который используется для обозначения, будет конкурировать с одним из двоичных битов, необходимых для представления числа. Однако это было бы довольно необычно. Любая идея, почему VC++ считает это проблемой уровня 3? - person Mike Sadler; 31.01.2013
comment
@MikeSadler Преобразования между подписанными и неподписанными одного размера действительно приводят к неожиданностям, например. ui < -1 почти всегда будет правдой. В общем, по этой причине я избегаю беззнаковых типов — нецензурных выражений. - person James Kanze; 31.01.2013

$18.2/6. Тип size_t — это определяемый реализацией тип целого числа без знака, который достаточно велик, чтобы содержать размер любого объекта в байтах.

$5.9 - В противном случае, если операнд, имеющий целочисленный тип без знака, имеет ранг больше или равен рангу типа другого операнда, операнд с целочисленным типом со знаком должен быть преобразован в тип операнда с целым числом без знака type. В первой части bool преобразуется в int перед преобразованием, как указано в стандарте C++.

Итак, это означает, что «i» преобразуется в тип «size_t» (при условии, что size_t имеет тип «unsigned int» или больше). Затем результаты типа «unsigned int» преобразуются в «bool» (тип result).

Обратите внимание, что в Стандарте указано, что ранг signed int и unsigned int одинаков.

Обратитесь к Разделам 4 и 5 стандарта C++ за точными правилами преобразования/продвижения.

person Chubsdad    schedule 30.01.2013
comment
Спасибо, @Chubsdad. Должен сказать, что мне сложно полностью понять эти стандарты, например, юридический английский. Означают ли 5,9 доллара, что наихудший случай, описанный в моем вопросе, может быть реализован? Можно ли преобразовать подписанное целое число (спасибо @H2CO3) в беззнаковое целое с радикально другой величиной, а затем неправильно (или, по крайней мере, неожиданно) сравнить его с другим беззнаковым целым числом? - person Mike Sadler; 31.01.2013