Как автоматическое распознавание короткого от длинного во время компиляции?

Я очень рад использовать auto переменные в моих программах C++. Я знаю переменные, объявленные с помощью правил использования auto использования, чтобы выводить типы переменных, но я смущен тем, как это работает для числовых типов. Предположим, что у меня есть:

auto foo = 12;

Тип foo может разумно быть int или даже unsigned char. Но предположим, что позже в моей программе я сделаю некоторую математику и присвою foo значение 4 миллиарда. В этот момент я бы хотел, чтобы foo стал типом unsigned int или, возможно, long.

Как компиляторы могут ожидать значения, которые будут назначены позже в программе?

Ответ 1

Компилятор работает с информацией, которая в вашем случае является целым литералом 12. Таким образом, он выводит foo на тип int. Он ничего не ожидает. Вы можете использовать соответствующий суффикс целочисленного литерала:

auto foo = 12ul;

чтобы заставить foo выводиться как unsigned long. Вы не можете определить переменную типа int а затем по строке ожидать, что компилятор каким-то образом изменит ее на другой тип только потому, что вы назначили другое значение, которое не будет вписываться в ранее использованный тип. Если вы это сделали, это просто приведет к переполнению целых чисел, что является неопределенным поведением.

Для получения дополнительной информации о предмете ознакомьтесь с инструкцией автоматического указателя и указателем вывода типа aut.

Ответ 2

"Тип foo может разумно быть int или даже unsigned char"

Нет, не может. Каждое выражение в C++ имеет тип, и это четко определено на языке. В вашем случае выражение является целым литералом, поэтому тип соответствует литералу. Какой тип он определен, определяется правилами:

Тип литерала

Тип целочисленного литерала - это первый тип, в котором значение может поместиться, из списка типов, который зависит от того, какая числовая база и какой целочисленный суффикс был использован.

нет суффикса - int, long int, long long int (поскольку C++ 11)

"Как компиляторы могут ожидать значения, которые будут назначены позже в программе?"

Это не может. Тип определяется при объявлении переменной, и ее нельзя изменить позже.

Ответ 3

Тип foo может разумно быть int или даже unsigned char

Это может быть много, но на самом деле это только одно.

Целочисленный литерал 12 имеет тип int.

Период.

Но предположим позже в моей программе, я делаю некоторую математику и присваиваю foo значение 4 миллиарда. В этот момент я хотел бы, чтобы foo имел тип unsigned int или, возможно, длинный. Как компиляторы могут ожидать значения, которые будут назначены позже в программе?

Они не могут, и они этого не делают. Тип foo не изменится. foo не имеет типа auto (нет такой вещи); он имеет тип int. Ваша программа впредь будет выглядеть так, как если бы вы написали int foo = 12; , Вывод/автоматизация заканчивается.

Ответ 4

В этот момент я хотел бы, чтобы foo имел тип unsigned int или, возможно, long.

Это не то, как язык работает. Переменная не может изменить ее тип во время выполнения. Если вы определяете и инициализируете переменную как auto foo = 12; , это означает то же самое, что и int foo = 12; , независимо от каких-либо будущих назначений, поскольку тип 12 является int.

Как компиляторы могут ожидать значения, которые будут назначены позже в программе?

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

Ответ 5

Мой совет заключается в том, что это нехорошее место для использования auto. Вы знаете, какие факторы определяют тип, который вам нужен, и они не могут быть выведены из непосредственного контекста. (Однако, если вы можете написать свои переменные как одиночные статические назначения, которые никогда не будут.)

Если вы знаете, что переменная должна иметь возможность хранить не менее 4 миллиардов, объявите ее как unsigned long или long long int. Или, если вы действительно хотите защитить код от неудачного выбора ширины этих типов (например, платформы long 32 бита для поддержки устаревшего кода, но размер родного слова - 64 бита), объявите его как uint_fast32_t или int_fast64_t. Или, если вам нужен самый маленький, а не самый быстрый, uint_least32_t. (Иногда самый быстрый код - тот, который хранит большинство значений в кеше!)

Если вы действительно хотите, это самый быстрый подписанный или неподписанный тип, который может содержать значение 4 миллиарда, скажите, что вы имеете в виду!

Ответ 6

Лично я бы не использовал auto для этих непосредственных констант, но где значение исходит из другого вызова метода или назначается из другой переменной.

Если вам нужен способ определить переменную для соответствия другому типу переменной, чтобы вы могли взаимодействовать с ней, но вы хотите назначить постоянное значение, тогда используйте decltype для обеспечения совместимости его размера:

decltype(otherVar) myVar = 1234;
myVar += otherVar;  // will work just as well as otherVar += myVar

В любом случае тип задается константой литерала, а не декорированный 12 определяет int.

Тем не менее, вы можете украсить свою константу U, сделать ее без знака, или L, чтобы сделать ее длинной, или даже LL, чтобы сделать ее сверхдолгой. К сожалению, нет никакого эквивалента, чтобы заставить его коротко или char.