Во-первых, спецификация заключается в том, что он вернет значение меньше, равно или больше 0, не обязательно -1или 1. Во-вторых, возвращаемые значения - это r-значения, подлежащие полному продвижению, поэтому возвращать что-то меньшее нет смысла.
В C ++ (как и в C) каждое выражение является либо rvalue, либо lvalue. Исторически эти термины относятся к тому факту, что lvalue появляются слева от присваивания, тогда как as rvalues могут появляться только справа. Сегодня простое приближение для неклассовых типов состоит в том, что lvalue имеет адрес в памяти, а rvalue - нет. Таким образом, вы не можете взять адрес rvalue, а cv-квалификаторы (условие «доступ») не применяются. В терминах C ++ rvalue, не имеющий типа класса, является чистым значением, а не объектом. Возвращаемое значение функции - rvalue, если оно не имеет ссылочного типа. (Неклассовые типы, которые помещаются в регистр, почти всегда будут возвращаться, например, в регистре, а не в памяти.)
Для типов классов проблемы немного сложнее из-за того, что вы можете вызывать функции-члены по rvalue. Это означает, что rvalues фактически должны иметь адреса для this
указателя и могут быть квалифицированы cv, поскольку cv-квалификация играет роль в разрешении перегрузки. Наконец, C ++ 11 вводит несколько новых различий для поддержки ссылок rvalue; они также в основном применимы к типам классов.
Под интегральным продвижением понимается тот факт, что когда целочисленные типы, меньшие чем an int, используются в качестве r-значений в выражении, в большинстве контекстов они будут повышены до int. Таким образом, даже если short a, b;в выражении объявлена переменная a
+ b, оба aи bповышаются intдо того, как произойдет добавление. Точно так же, если я пишу a < 0, сравнение выполняется по значению a, преобразованному в int. На практике очень мало случаев, когда это имеет значение, по крайней мере, на машинах с дополнением до 2, где целочисленная арифметика оборачивается (т.е. все, кроме очень немногих экзотических вещей, сегодня - я думаю, что мэйнфреймы Unisys являются единственными оставшимися исключениями). Тем не менее, даже на более распространенных машинах:
short a = 1;
std::cout << sizeof( a ) << std::endl;
std::cout << sizeof( a + 0 ) << std::endl;
должен давать разные результаты: первый эквивалент
sizeof( short ), второй sizeof( int )(из-за целостного продвижения).
Эти две проблемы формально ортогональны; rvalues и lvalues не имеют ничего общего с интегральным продвижением. За исключением ... интегральное продвижение применяется только к rvalue, и в большинстве (но не во всех) случаях, когда вы использовали бы rvalue, результатом было бы полное продвижение. По этой причине действительно нет причин возвращать числовое значение в чем-то меньшем, чем int. Есть даже очень веская причина не возвращать его как символьный тип. Например <<, перегруженные операторы часто ведут себя по-разному для типов символов, поэтому вы хотите возвращать символы только как типы символов. (Вы можете сравнить разницу:
char f() { return 'a'; }
std::cout << f() << std::endl; // displays "a"
std::cout << f() + 0 << std::endl; // displays "97" on my machine
Разница в том, что во втором случае добавление вызвало интегральное продвижение, что приводит <<к выбору другой перегрузки .