Подтвердить что ты не робот

Почему auto выводится на int вместо uint16_t

У меня есть следующий код:

uint16_t getLastMarker(const std::string &number);
...
const auto msgMarker = getLastMarker(msg.number) + static_cast<uint16_t>(1);
static_assert(std::is_same<decltype(msgMarker), const int>::value, "Should fail");
static_assert(std::is_same<decltype(msgMarker), const uint16_t>::value, "Should not fail");

и я ожидаю, что первое утверждение потерпит неудачу, а второе - нет. Однако gcc 4.9.2 и clang 3.6 делают обратное. Если я использую uint16_t вместо auto в моем коде, то утверждение завершается неудачно, а другое успешно выполняется.

P.S. Первоначально у меня было только 1 вместо static_cast<uint16_t>(1) и считалось, что проблема вызвана тем, что числовой литерал 1 имеет тип int, но неправильное утверждение не срабатывает даже после явного приведения здесь.

4b9b3361

Ответ 1

Дополнение будет выполнять обычные арифметические преобразования в своих операндах, которые в этом случае приведут к тому, что операнды будут продвинуты до int из-за целые рекламные акции, и результатом будет также int.

Вы можете использовать uint16_t вместо auto, чтобы принудительно выполнить преобразование, или в общем случае вы можете использовать static_cast.

Для обоснования того, почему тип, меньший, чем int, продвигается к более крупным типам, см. Почему короткое преобразование в int перед арифметическими операциями в C и С++?.

Для справки, из проекта стандартного раздела С++ 5.7 Аддитивные операторы:

[...] Обычные арифметические преобразования выполняются для операндов арифметический или перечисляемый тип [...]

и из раздела 5 Выражения:

[...] В противном случае интегральные акции (4.5) должны выполняться на оба операнда. 59 Затем применяются следующие правила: к продвинутым операндам [...]

и из раздела 4.5 Интегральные рекламные акции (внимание мое):

Значение целочисленного типа, отличного от bool, char16_t, char32_t или wchar_t , чей целочисленный ранг преобразования (4.13) меньше ранга int может быть преобразован в prvalue типа int, если int может представлять все значения типа источника; в противном случае исходное значение может преобразуется в prvalue типа unsigned int.

Предполагая, что int больше 16-бит.

Ответ 2

Арифметические операции не работают ни на одном типе, меньшем, чем int. Таким образом, если uint16_t меньше, чем int, перед выполнением добавления ему будет присвоен int (или, возможно, более крупный тип, если необходимо, чтобы сопоставить другой операнд).

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