левый операнд операции запятая ($$R.5.18) или в качестве второго или
третьего операнда в операции ?: ($$R.5.16).

    R.3.6.2 Производные типы



Существует потенциально бесконечное число производных типов, которые
строятся из основных типов следующими способами:
массив объектов данного типа, $$R.8.4;
функции, имеющие параметры данного типа и возвращающие объекты
данного типа, $$R.8.2.5;
указатели на объекты или функции данного типа, $$R.8.2.1;
ссылки на объекты или функции данного типа, $$R.8.2.2;
константы, являющиеся значениями данного типа, $$R.7.1.6;
классы, содержащие совокупность объектов различных типов ($$R.9),
набор функций для управления этими объектами ($$R.9.3) и
и список ограничений на доступ к этим объектам и функциям, $$R.11;
структуры, которые являются классами без стандартных ограничений
на доступ, $$r.11;
объединения, которые являются структурами, способными содержать
в разное время объекты различных типов, $$R.9.5;
указатели на члены классов, которые задают члены данного типа
среди всех объектов данного класса, $$R.8.2.3.
В общем случае указанные методы построения объектов могут применяться
рекурсивно, ограничения приведены в $$r.8.2.1, $$R.8.2.4, $$R.8.2.5
и $$R.8.2.2.
Про указатель на объекты типа T говорят "указатель на на T". Например,
про указатель на объект типа int говорят "указатель на int", а
указатель на объект класса X называется "указатель на X".
Объекты типа void* (указатель на void), const void* и
volatile void* могут использоваться как указатели на объекты
неизвестного типа. Объект типа void* должен иметь достаточно памяти,
чтобы хранить указатель на любой объект.
Все фрагменты руководства, говорящие об "указателях", не относятся
к указателям на члены, за исключением указателей на статические
члены.

    R.3.6.3 Имена типов



Основные и производные типы можно поименовать с помощью механизма
typedef ($$R.7.1.3), а семейство типов и функций можно задать и
поименовать с помощью механизма шаблона типов ($$R.14).

    R.3.7 Адреса



Любой объект - это некоторая область памяти, адрес - выражение,
ссылающееся на объект или функцию. Очевидным примером адреса будет
имя объекта. Существуют операции, порождающие адреса, например,
если E выражение типа указатель, то *E - адресное выражение,
соответствующее объекту, на который указывает E. Термин "адрес"
("lvalue" т.е. left value - левая величина) появляется из оператора
присваивания E1 = E2, где левый операнд E1 должен "адресовать"
изменяемую переменную. При обсуждении всех операций в $$R.5 указывается
применимы ли они к адресным операндам и порождают ли они сами адреса.
Адрес может изменяться, если он не является именем функции,
именем массива или const.

    R.4 Стандартные преобразования



Некоторые операции в зависимости от своих операндов могут вызвать
преобразование значения операнда от одного типа к другому. Здесь
описываются преобразования, вызванные самыми обычными операциями,
и объясняется каковы могут быть результаты таких преобразований.
По мере надобности будут даны дополнительные объяснения при
обсуждении каждой операции. Подобные преобразования также происходят
при инициализации ($$R.8.4, $$R.8.4.3, $$R.12.8, $$R.12.1).
В $$R.12.3 и $$R.13.2 описываются преобразования, заданные
пользователем, и их соотношения со стандартными преобразованиями.
В результате преобразования может получиться адрес, только если
результат есть ссылка ($$R.8.2.2).

    R.4.1 Стандартные преобразования для целочисленных



Всюду, где требуется целое, можно использовать char, short int,
элемент перечисления ($$R.7.2) или битовое поле ($$R.9.6), причем
в знаковом и беззнаковом вариантах. Если int может представлять
все значения исходного типа, значение преобразуется к int, иначе
оно преобразуется к unsigned int. Это называется стандартным
преобразованием для целочисленных.

    R.4.2 Преобразования целочисленных



Если целое преобразуется в беззнаковый тип, то полученное значение
есть наименьшее беззнаковое целое, совпадающее с целым со знаком
по (mod 2**n), где n есть число битов в представлении беззнакового
целого. Для представления в дополнительном коде это преобразование
лишь концептуальное, никаких изменений в двоичном представлении
в действительности не происходит.\
Если целое преобразуется к знаковому типу, значение не меняется,
при условии, что его можно представить с помощью нового типа,
иначе значение определяется реализацией.

    R.4.3 Значения с плавающей точкой и двойной точностью



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

    R.4.4 Целочисленные и числа с плавающей точкой



Преобразование значения с плавающей точкой к целочисленному типу
сводится к "усечению", т.е. отбрасыванию дробной части. Такие
преобразования зависят от машины, в частности в какую сторону будет
проходить усечение для отрицательных чисел определяется на разных
машинах по разному. Результат считается неопределенным, если
значение нельзя представить в целочисленном типе.
Преобразования целочисленных значений к значениям с плавающей
точкой математически корректны настолько, насколько это позволяет
система команд. Может произойти потеря точности, если целочисленное
значение нельзя точно представить как значение с плавающей точкой.


R.4.5 Арифметические преобразования

Для большинства операций преобразования операндов и тип результата
определяются одними и и теми же правилами. Это правило можно назвать
"обычными арифметическими преобразованиями".
Если один из операндов есть long double, другой операнд
преобразуется в long double.
Иначе, если один из операндов есть double, другой операнд
преобразуется в double.
Иначе, если один из операндов есть float, другой операнд
преобразуется в float.
Иначе, если стандартные целочисленные преобразования ($$R.4.1)
происходят над обоими операндами.
Тогда, если один из операндов есть unsigned long, другой
операнд преобразуется в unsigned long.
Иначе, если один из операндов есть long int, а другой -
unsigned int, то при условии, что long int может представлять
все возможные значения unsigned int, значение unsigned int
преобразуется в long int, в противном случае оба операнда
преобразуются в unsigned long int.
Иначе, если один из операндов есть long, другой операнд
преобразуется в long.
Иначе, если один из операндов есть unsigned, другой операнд
преобразуется в unsigned.
Иначе, оба операнда должны быть int.

    R.4.6 Преобразования указателей



Всюду, где указатели ($$R.8.2.1) присваиваются, инициализируются,
сравниваются или используются иным образом, могут происходить
следующие преобразования:
Константное выражение ($$R.5.19), которое сводится к нулю,
преобразуется в указатель, обычно называемый пустым указателем.
Гарантируется, что значение такого указателя будет отлично от
любого указателя на объект или функцию.
Указатель на объект любого типа, не являющегося const или
volatile, можно преобразовать в void*.
Указатель на функцию можно преобразовать в void*, при условии,
что для void* отводится достаточно памяти, чтобы хранить этот
указатель.
Указатель на данный класс можно преобразовать в указатель на
доступный базовый класс данного класса ($$R.10), если такое
преобразование не содержит двусмысленность ($$R.10.1). Базовый
класс считается доступным, если доступны его общие члены ($$R.11.1).
Результатом преобразования будет указатель на объект типа базового
класса, вложенный в объект типа производного класса. Пустой указатель
(0) преобразуется сам в себя.
Выражение типа "массив T" может преобразовываться в указатель
на начальный элемент массива.
Выражение типа "функция, возвращающая T" преобразуется в "указатель
на функцию, возвращающую T", за исключением тех случаев, когда
оно используется как операнд адресной операции & или операции
вызова функции ().

    R.4.7 Преобразования ссылок



Всюду, где ссылки ($$R.8.2.2) инициализируются (включая передачу
параметров ($$R.5.2.2) и возврат значения функции ($$R.6.6.3)) или
используются иным образом, возможны следующие преобразования:
Ссылка на данный класс может быть преобразована в ссылку на доступный
базовый класс ($$R.10, $$R.11.1) данного класса ($$R.8.4.3),
при условии, что такое преобразование не содержит двусмысленности
($$R.10.1.1). Результатом преобразования будет ссылка на объект
базового класса, вложенный в объект производного класса.

    R.4.8 Указатели на члены



Всюду, где указатели на члены ($$R.8.2.3) инициализируются,
присваиваются, сравниваются или используются иным образом,
могут происходить следующие преобразования:
Константное выражение ($$R.5.19), которое сводится к нулю,
преобразуется в указатель на член. Гарантируется, что его
значение будет отлично от любых других указателей на члены.
Указатель на член данного класса можно преобразовать в
указатель на член производного от данного класса, при условии,
что допустимо обратное преобразование от указателя на член производного
класса в указатель член базового класса, и что оно выполнимо
однозначным образом ($$R.10.1.1).
Правило преобразования указателей на члены (т.е. от указателя на
член базового класса к указателю на член производного класса) выглядит
перевернутым, если сравнивать его с правилом для указателей на
объекты (т.е. от указателя на производный объект к указателю на
базовый объект) ($$R.4.6, $$R.10). Это необходимо для гарантии
надежности типов.
Отметим, что указатель на член не является указателем на объект
или указателем на функцию и правила преобразований таких указателей
не применимы для указателей на члены. В частности указатель на член
нельзя преобразовать в void*.

    R.5 Выражения



Здесь определяются синтаксис, порядок вычисления и назначение
выражений. Выражение - это последовательность операций и операндов,
которая задает вычисление. Вычисление может выдавать в качестве
результата значение и может вызывать побочные эффекты.
Операции могут быть перегружены, т.е. им может быть приписано значение,
когда они применяются к выражениям типа класс ($$R.9). Применение
перегруженных операций преобразуется в вызовы функций в соответствии
с описанием в $$R.13.4. Перегруженные операции подчиняются
синтаксическим правилам, определенным в этом разделе, но требования
к типу операнда, адресу и порядку вычисления заменяются на правила
вызова функции. Соотношения между операциями, типа ++a означает
a+=1, не гарантируются для перегруженных операций ($$R.13.4).
В этом разделе описано применение операций к типам, для которых
они не являются перегруженными. Перегрузка операций не может изменить
правила применения операций к типам, для которых такое применение
предусмотрено в самом языке.
Порядок вычисления подвыражений определяется приоритетом и порядком
применения операций. Обычные математические правила ассоциативности
и коммутативности операций действуют только, если операции
действительно ассоциативны или коммутативны. За исключением
оговоренных случаев порядок вычисления операндов конкретной операции
неопределен. В частности, если в выражении значение изменяется
дважды, результат выражения неопределен, если только порядок
выполнения не обеспечивается самими операциями, например:

i = v[i++]; // the value of `i' is undefined
i=7,i++,i++; // `i' becomes 9

Реакция на переполнение и деление на нуль при вычислении выражения
зависит от реализации. В большинстве существующих реализаций С++
игнорируется переполнение целых. Реакция на деление на нуль и
ошибки операций над числами с плавающей точкой варьируется от
машины к машине и обычно связана с соответствующими библиотечными
функциями.
Кроме оговоренных случаев, операнды типа const T, volatile T,
T&, const T& и volatile T& можно использовать, как если бы они
имели тип просто T. Аналогично, операнды типа T* const, T*volatile
можно использовать, как если бы они имели тип просто T*, за
исключением оговоренных случаев. Аналогично, просто тип T можно
использовать всюду, где требуется тип volatile T или const T.
Эти правила может применять в комбинации, так что const T* volatile
можно использовать там, где требуется T*, за исключением оговоренных
случаев. При рассмотрении разрешения перегрузки ($$R.13.2) такое
использование операций не считается стандартным преобразованием
операндов.
Если выражение имеет тип "ссылка на T" ($$R.8.2.2, $$R.8.4.3),
значение выражение есть объект типа "T", на который настроена
ссылка. Выражение является адресом. Ссылку можно представлять как
имя объекта.
Допустимы определенные пользователем преобразования объектов
класса в (и обратно) основные типы, указатели и т.д. ($$R.12.3)
Если они недвусмысленны ($$R.13.2), такие преобразования могут
применяться транслятором всегда, когда появляется объект типа класса
в качестве операнда операции, в качестве инициализирующего
выражения ($$R.8.4), в качестве выражения, задающего условие ($$R.6.4),
или в качестве выражения, используемого в операторе цикла ($$R.6.5),
или в качестве значения, возвращаемого функцией ($$R.6.6.3),
или в качестве параметра функции ($$R.5.2.2).

    R.5.1 Первичные выражения



Первичными выражениями являются литералы, имена и имена, определенные
с помощью операции разрешения области видимости ::.

первичное-выражение:
литерал
this
:: идентификатор
:: имя-функции-операции
:: уточненное-имя
( выражение )
имя

Литерал является первичным выражением. Его тип определяется
его видом ($$R.2.5).
В теле нестатической функции-члене ($$R.9.3) служебное слово
this обозначает указатель на объект, к которому относится вызов
функции. Служебное слово this нельзя использовать вне тела
функции-члена класса.
Операция :: , за которой следует идентификатор или
имя-операции-функции или уточненное-имя являются первичным
выражением. Его тип задается описанием идентификатора, имени
или имени-функции-операции. Результатом является идентификатор,
имя или имя-функции-операции. Результат является адресом, если
идентификатор является адресом. Идентификатор или имя-функции-операции
должны иметь файловую область видимости. С помощью операции ::
можно обращаться к типу, объекту, функции или элементу перечисления,
даже если обозначающий их идентификатор является скрытым ($$R.3.2).
Выражение в скобках является первичным выражением, тип и значение
которого идентичны им же у выражения без скобок. Наличие скобок
не влияет на то, является выражение адресом или нет.
Понятие имя - это определенное первичное-выражение, которое
может появляться только после . и -> ($$R.5.2.4):

имя:
идентификатор
имя-функции-операции
имя-функции-преобразования
~имя-класса
уточненное-имя

Идентификатор есть имя, при условии что он описан надлежащим образом
($$R.7). Понятие имя-функции-операции описано в ($$R.13.4), а
понятие имя-функции-преобразования в ($$R.12.3.2). Конструкция
~имя-класса обозначает деструктор ($$R.12.4).

уточненное-имя:
уточняющее-имя-класса :: имя

Понятие уточняющее-имя-класса, за которым следует :: и имя члена
этого класса ($$R.9.2), или члена базового по отношению к данному
класса ($$R.10) является уточненное-имя. Его тип есть
тип члена, а результат выражения есть этот член. Результат является
адресом, если таковым является член. Имя класса может быть скрыто
другим именем (не типа), в таком случае все равно имя класса
доступно и его можно использовать. Если используется
имя-класса::имя-класса или имя-класса::~имя-класса, оба понятия
имя-класса должны обозначать один и тот же класс. С помощью такой
записи обозначаются конструкторы ($$R.12.1) и деструкторы ($$R.12.4)
соответственно. Можно использовать уточняющие имена
неоднократно, например, N1::N2::N3::n, чтобы обозначать вложенные
типы ($$R.9.7).

    R.5.2 Постфиксные выражения



Постфиксные выражения применяются слева направо.
постфиксное-выражение:
первичное-выражение
постфиксное-выражение [ выражение ]
постфиксное-выражение ( список-выражений opt )
имя-простого-типа ( список-выражений opt )
постфиксное-выражение . имя
постфиксное-выражение -> имя
постфиксное-выражение ++
постфиксное-выражение --
список-выражений:
выражение-присваивания
список-выражений , выражение-присваивания

    R.5.2.1 Индексация



Постфиксное выражение, за которым следует выражение в квадратных
скобках, является постфиксным выражением. Интуитивный смысл его
индексирование. Первое из выражений должно иметь тип "указатель на T",
а второе быть целочисленного типа. Тип результата есть "T". Выражение
E1[E2] совпадает (по определению) с выражением *((E1) + (E2)).
Подробности операций * и + даны в $$R.5.3 и $$R.5.7, а массивы
обсуждаются в $$R.8.2.4.

    R.5.2.2 Вызов функции



Вызов функции является постфиксным выражением, за которым следует,
возможно пустой, список выражений в скобках, разделенных запятой.
Эти выражения образуют фактические параметры функции. Постфиксное
выражение должно иметь тип "функция, возвращающая T", "указатель на
функцию, возвращающую T" или "ссылка на функцию, возвращающую T",
а результат операции вызова имеет тип "T".
При вызове функции происходит инициализация каждого формального
параметра ($$R.8.4.3, $$R.12.8, $$r.12.1) фактическим параметром.
Производятся стандартные ($$R.4) и заданные пользователем ($$R.12.3)
преобразования типа. В функции может изменяться значения непостоянных
формальных параметров, но эти изменения не могут повлиять на значения
фактических параметров, кроме того случая, когда формальный параметр
имеет тип ссылки без спецификации const ($$R.8.2.2). Если формальный
параметр имеет тип ссылки при необходимости может создаваться
временная переменная ($$R.7.1.6, $$R.2.5,$$R.2.5.4,$$R.8.2.4,
$$R.12.2). Добавим, что возможно изменение непостоянных объектов с
помощью параметров-указателей.
Функцию можно описать таким образом, что она сможет использовать
меньшее число параметров (определив параметры по умолчанию $$R.8.2.6)
или большее число параметров (с помощью эллипсиса ... $$R.8.2.5),
чем было указано при определении функции ($$R.8.3).
Функцию можно вызвать только, если описание ее доступно в той области
видимости, где происходит вызов. Отсюда следует, всякий формальный
параметр, соответствующий некоторому фактическому параметру, должен
быть доступен, если не считать эллипсис (...).
Перед вызовом всякий фактический параметр типа float, для которого
нет формального параметра, преобразуется к типу double, а типа
char, short, перечисления или битовое поле, для которого нет
формального параметра, преобразуется к типу int или unsigned
согласно стандартным преобразованиям целочисленных ($$R.4.1).
Объект, являющийся классом и не имеющий описания формального параметра,
передается при вызове как структура данных.
Объект, являющийся классом и имеющий описание формального
параметра передается с помощью инициализации формального параметра
фактическим параметром, которая происходит перед выполнением
функции посредством вызова конструктора ($$R.12.2, $$R.12.8).
Порядок вычислений параметров неопределен и учтите, что он
может быть различен у разных трансляторов. Все побочные эффекты
выражений фактических параметров могут происходить перед началом
выполнения функции. Порядок вычисления постфиксных выражений и
списка выражений параметров неопределен.
Допустимы рекурсивные вызовы.
Операция вызова функции порождает адрес только, если тип
результата есть адрес.

    R.5.2.3 Явные преобразования типа



Конструкция имя-простого-типа ($$R.7.1.6), за которой следует
список-выражений в скобках образует значение указанного типа
с учетом списка выражений. Если список выражений содержит более
одного значения, тип должен быть классом с конструктором, описанным
соответствующим образом ($$R.8.4, $$R.12.1).
Конструкция имя-простого-типа ($$R.7.1.6), за которой следует
пара скобок (пустая), образует значение указанного типа. Если тип
является классом с конструктором, описанным соответствующим образом,
будет вызван этот конструктор, в противном случае результатом
будет неопределенное значение указанного типа, см. так же ($$R.5.4).

    R.5.2.4 Доступ к члену класса



Постфиксное выражение, за которым следует точка (.) и имя, является
постфиксным выражением. Первое выражение должно быть объектом типа
класс, а имя должно быть именем члена этого класса. Результатом будет
поименованный член объекта и он будет адресом, если член является
адресом.
Постфиксное выражение, за которым следует стрелка (->) и имя,
является постфиксным выражением. Первое выражение должно быть
указателем на объект типа класс, а имя должно быть именем члена
этого класса. Результатом будет поименованный член объекта, на
который настроен указатель и он будет адресом, если член является
адресом. Значит выражение E1->MOS тоже самое, что (*E1).MOS.
Обратите внимание, что "объекты типа класс" могут быть
структурами ($$R.9.2) или объединениями ($$R.9.5). Классы обсуждаются
в $$R.9.

    R.5.2.5 Инкремент и декремент



Значение, получаемое в результате применения постфиксной операции ++,
есть значение операнда. Операнд должен быть изменяемым адресом.
Тип операнда должен быть арифметический или тип указателя. После
выборки результата (для дальнейшего использования) объект увеличивается
на 1. Тип результата совпадает с типом операнда, но не является
адресом (см. так же $$R.5.7 и $$R.5.17).
Постфиксная операция -- сводится к операции декремента (уменьшение
на 1) и аналогична операции ++.

    R.5.3 Унарные операции



Выражения с унарными операциями выполняются справа налево.

унарное-выражение:
постфиксное-выражение
++ унарное выражение
-- унарное выражение
унарная-операция выражение-приведения
sizeof унарная-операция
sizeof ( имя-типа )
выражение-размещения
выражение-освобождения
унарная-операция: один из
* & + - ! ~

Унарная операция * означает косвенность: выражение должно быть
указателем, а результат является адресом, ссылающимся на объект, на
который указывает выражение. Если тип выражения есть "указатель на T",
то тип результата будет "T".
Результатом унарной операции & будет указатель на ее операнд.
Операнд должен быть функцией или адресом или конструкцией
уточненное-имя. Для первых двух случаев, если тип выражения
есть "T", то тип результата будет "указатель на T". В частности,
адрес объекта типа const T имеет тип const T*, тоже верно для
volatile. Для случая уточненное имя если член класса "C" не является
статическим и имеет тип "T", то тип результата операции будет
"указатель на член C типа T". Для статических членов типа T
результатом будет обычный "указатель на T". Адрес перегруженной
функции ($$R.13) можно брать только при инициализации или
присваивании, в котором левая часть однозначно определяет какая
версия перегруженной функции имеется ввиду ($R13.3).
Операнд унарной операции + должен быть арифметического типа
или типа указатель и результатом будет значение операнда. Для
целочисленных операндов производится стандартное преобразование
целочисленных. Тип результата есть тип преобразованного операнда.
Операнд унарной операции - должен иметь арифметический тип и
результатом будет изменение знака операнда. Для целочисленных
операндов выполняется стандартное преобразование целочисленных.
Операция для беззнаковых величин выполняется с помощью вычитания
значения операнда из 2**n, где n число битов в представлении
преобразованного операнда. Тип результата есть преобразованного
операнда.
Операнд операции логического отрицания ! должен иметь
арифметический тип или быть указателем, результат равен 1, если
значение операнда есть 0, и равен 0, если операнд не равен 0.
Тип результата есть int.
Операнд операции ~ должен иметь целочисленный тип, результатом
будет обращение двоичного представления операнда. Выполняются
стандартные преобразования целочисленных. Тип результата есть
тип преобразованного операнда.

    R.5.3.1 Инкремент и декремент



Операнд префиксной операции ++ увеличивается на 1. Операнд должен
быть изменяемым адресом. Тип операнда должен быть арифметическим
или указателем. Результатом является новое значение операнда,
оно считается адресом. Выражение ++x эквивалентно x+=1. Для
уточнения преобразований можно обратиться к описанию сложения
($$R.5.7) и операций присваивания ($$R.5.17).
Префиксная операция -- сводится к уменьшению на 1 и выполняется
аналогично префиксной операции ++.

    R.5.3.2 Операция sizeof



Операция sizeof вычисляет размер своего операнда в байтах. Операнд
должен быть или выражением, которое не вычисляется, или именем типа
в скобках. Операцию sizeof нельзя применять к функции, битовому полю,
неопределенному классу, типу void или к массиву с неуказанными
границами индексов. Байт никак не определяется языком, кроме как
результата операции sizeof, именно sizeof(char) есть 1.
Если операция применяется к ссылке, результатом будет размер
объекта, на который настроена ссылка. Если она применяется к классу,
результатом будет размер объекта этого класса в байтах с учетом
всех дополнительных байтов, которые потребуется для размещения
такого объекта в массиве. Размер любого класса или объекта класса
больше нуля. В случае массива операция выдает полное число байтов
в массиве. Отсюда следует, что размер массива из n элементов равен
размеру элемента, умноженному на n.
Операция sizeof может применяться к указателю на функцию, но не