макровызова. В символьной константе или строке литералов, входящих
в параметр, перед каждым вхождением \ или " вставляется символ \.
Например, если есть макроопределения

#define path(logid,cmd) "/usr/" #logid "/bin/" #cmd

то макровызов

char* mytool=path(joe,readmail);

приведет к такому результату:

char* mytool="/usr/" "joe" "/bin/" "readmail";

После конкатенации соседних строк ($$R.16.1) получим:

char* mytool="/usr/joe/bin/readmail";

    R.16.3.2 Операция ##



Если в строке замены между двумя лексемами, одна из которых
представляет параметр макроопределения, появляется операция
##, то сама операция ## и окружающие ее обобщенные пробелы
удаляются. Таким образом, результат операции ## состоит в
конкатенации.
Пусть есть макроопределение,

#define inherit(basenum) public Pubbase ## basenum, \
private Privbase ## basenum

тогда макровызов

class D : inherit(1) { };

приведет к такому результату:

class D : public Pubbase1, Privbase1 { };

Макроопределение, которое в строке замены соседствует с
##, не подлежит подстановке, однако, результат конкатенации может
использоваться для подстановки. Приведем пример. Пусть есть
определения:

#define concat(a) a ## ball
#define base B
#define baseball sport

Тогда макровызов

concat(base)

даст в результате

sport

а вовсе не

Bball

    R.16.3.3 Повторный просмотр и дальнейшие подстановки



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

    R.16.3.4 Область видимости макроимен и конструкция #undef



После появления макроопределения идентификатор из него считается
определенным и остается в текущей области видимости (независимо от
правил областей видимости в С++) до конца единицы трансляции или
пока его определение не будет отменено с помощью команды #undef.
Команда #undef имеет вид:

#undef идентификатор

Она заставляет препроцессор "забыть" макроопределение с этим
идентификатором. Если указанный идентификатор не является
определенным в данный момент макроименем, то команда #undef
игнорируется.

    R.16.4 Включение файлов



Управляющая строка вида:

#include <имяфайла>

приводит к замене данной строки на содержимое файла с указанным именем.
Поиск указанного файла проходит в определенной последовательности
частей архива системы и определяется реализацией.
Аналогично, управляющая строка вида:

#include "имяфайла"

приводит к замене данной строки на содержимое файла с указанным
именем. Поиск этого файла начинается в особых (системных) частях
архива, указанных в начале последовательности поиска. Если там он
не найден, то поиск файла идет по всей последовательности, как если бы
управляющая строка имела вид:

#include <имяфайла>

В имени файла, ограниченном символами < и > нельзя использовать
символы конца строки или >. Если в таком имени появится один из
символов ', \, или ", а также последовательность символов /* или //,
то результат считается неопределенным.
В имени файла, ограниченном парой символов " нельзя использовать
символы конца строки или ", хотя символ > допустим. Если в таком
имени появится символ ' или \ или последовательность /* или //,
то результат считается неопределенным.
Если команда

#include строка-лексем

имеет вид, соответствующий ни первой, ни второй управляющей строке,
то лексемы препроцессора, заданные в этой команде обрабатываются как
обычный текст. В результате должна получиться команда, вид которой
соответствует одному из приведенных. Она и будет выполнена как положено.
Команда #include может быть в файле, который сам появился в
результате выполнения другой команды #include.
Реализация может накладывать ограничение на глубину вложенности
команды #include во входных файлах программы, которые приходится
читать для выполнения первоначальной команды #include в одном из
входных файлов.

    R.16.5 Условная трансляция



С помощью препроцессора можно организовать условную трансляцию
программы. Синтаксически это задается следующим образом:

условное:
часть-if части-elif opt часть-else opt строка-endif

часть-if:
строка-if текст

строка-if:
# if выражение-константа
# ifdef идентификатор
# ifndef идентификатор

части-elif:
строка-elif текст
части-elif строка-elif текст

строка-elif:
# elif выражение-константа

часть-else:
строка-else текст

строка-else:
# else

строка-endif:
# endif

Константные выражения в #if и #elif (если эти части есть)
вычисляются в порядке их задания в тексте до тех пор, пока одно
из них не окажется отличным от нуля. Операторы С++, следующие за
строкой, в которой выражение оказалось равным нулю, не транслируются.
Команды препроцессора, идущие за этой строкой игнорируются.
После того, как найдена команда с ненулевым значением выражения,
текст всех последующих частей #elif и #else (т.е. операторы С++ и
команды препроцессора) игнорируется. Текст, относящийся к первой
команде с ненулевым значением выражения подлежит обычной препроцессорной
обработке и трансляции. Если значения всех выражений, указанных в #if
и #elif, оказались равными нулю, тогда обычной обработке подлежит текст,
относящийся к #else.
В выражении-константе, которое встретилось в #if или #elif
можно использовать унарную операцию defined, причем в двух
вариантах:

defined идентификатор

или

defined (идентификатор)

Если эта операция применяется к идентификатору, который был определен
с помощью команды #define, и если это определение не было отменено
командой #undef, то результат равен 1, иначе результат равен 0.
Сам идентификатор defined нельзя переопределить, нельзя и отменить
его определение.
После применения операций defined происходит раскрытие всех
всех макроопределений, имеющихся в константном выражении
см. $$R.16.3. В результате должно получиться целочисленное
выражение-константа, отличающееся от определения в $$R.5.19 тем,
что типы int и unsigned int рассматриваются как long и unsigned long
соответственно, а кроме того в этом выражении не должно быть
операций приведения, sizeof или элемента перечисления.
Управляющая строка

#ifdef идентификатор

эквивалентна строке

#if defined идентификатор

а управляющая строка

#ifndef идентификатор

эквивалентна строке

#if !defined идентификатор

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

    R.16.6 Управление строками



Для удобства написания программ, порождающих текст на С++, введена
управляющая строка вида:

#line константа "имяфайла" opt

Она задает значение предопределенному макроимени __LINE__ ($$R.16.10),
которое используется в диагностических сообщениях или при
символической отладке; а именно: номер следующей строки
входного текста считается равным заданной константе, которая должна
быть десятичным целым числом. Если задано "имяфайла", то значение
макроимени __FILE__ ($$R.16.10) становится равным имени указанного
файла. Если оно не задано, __FILE__ не меняет своего значения.
Макроопределения в этой управляющей строке раскрываются до
выполнения самой команды.

    R.16.7 Команда error



Строка вида:

#error строка-лексем

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

    R.16.8 Команда pragma



Строка вида:

#pragma строка-лексем

заставляет реализацию вести себя некоторым определенным образом
при условии что реализация "понимает" эту строку. Любая
нераспознанная строка #pragma игнорируется.

    R.16.9 Пустая директива



Команда препроцессора вида

#

не оказывает никакого действия.

    R.16.10 Предопределенные макроимена



В процессе трансляции определенную информацию содержат следующие
предопределенные макроимена.

__LINE__ десятичная константа, содержащая номер текущей строки
текста программы на С++.
__FILE__ строка литералов, представляющая имя транслируемого
входного файла.
__DATE__ строка литералов, представляющая дату трансляции в виде
"Mmm dd yyyy" или "Mmm d yyyy", если число меньше 10,
(здесь Mmm задает месяц, dd - день, а yyyy - год).
__TIME__ строка литералов, представляющая время трансляции в виде
"hh:mm:ss", (здесь hh задает часы, mm - минуты, а
ss - секунды).

Кроме того, считается определенным при трансляции программы на С++
макроимя __cplusplus.
Перечисленные макроимена нельзя как переопределять, так и отменять их
определения.
Макроимена __LINE__ и __FILE__ можно определить с помощью команды
#line ($$R.16.6).
Определено ли макроимя __STDC, и если да, то каково его значение,
зависит от реализации.

    R.17 Приложение A: Сводка грамматики



Это приложение не относится к справочному руководству языка и
не является определением конструкций C++.
Она только должно служить более полному пониманию С++. Нельзя
рассматривать его как точное определение языка, так как описанная здесь
грамматика допускает произвольное множество конструкций, каждая из
которых законна для С++. Чтобы различать выражения и описания,
следует применять правила разрешения неопределенности ($$r.6.8,
$$R.7.1, $$R.10.1.1). Далее, для отсеивания синтаксически правильных,
но бессмысленных, конструкций следует применять правила контроля
доступа, разрешения неопределенности и контроля типа.

    R.17.1 Служебные слова



В описаниях: typedef ($$R.7.1.3), класса ($$R.9), перечисления
($$R.7.2), шаблона типа - ($$R.14) введены новые, зависящие от
контекста, служебные слова, а именно:

имя-класса:
идентификатор

имя-перечисления:
идентификатор

имя-typedef:
идентификатор

Отметим, что имя-typedef, обозначающее класс, является в то же
время конструкцией имя-класса ($$R.9.1).

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



выражение:
выражение-присваивания
выражение, выражение-присваивания

выражение-присваивания:
выражение-условия
унарное-выражение операция-присваивания выражение-присваивания
операция-присваивания: один из
= *= /= %= += -= >>= <<= &= ^= |=
выражение-условия:
логическое-выражение-ИЛИ
логическое-выражение-ИЛИ ? выражение : выражение-условия

логическое-выражение-ИЛИ:
логическое-выражение-И
логическое-выражение-ИЛИ || логическое-выражение-И

логическое-выражение-И:
выражение-ИЛИ
логическое-выражение-И && выражение-ИЛИ

выражение-ИЛИ:
выражение-исключающего-ИЛИ
выражение-ИЛИ | выражение-исключающего-ИЛИ

выражение-исключающего-ИЛИ:
выражение-И
выражение-исключающего-ИЛИ ^ выражение-И

выражение-И:
выражение-равенства
выражение-И & выражение-равенства

выражение-равенства:
выражение-отношения
выражение-равенства == выражение-отношения
выражение-равенства != выражение-отношения

выражение-отношения:
сдвиговое-выражение
выражение-отношения < сдвиговое-выражение
выражение-отношения > сдвиговое-выражение
выражение-отношения <= сдвиговое-выражение
выражение-отношения >= сдвиговое-выражение

сдвиговое-выражение:
аддитивное-выражение
сдвиговое-выражение << аддитивное выражение
сдвиговое-выражение >> аддитивное выражение

аддитивное-выражение:
мультипликативное-выражение
аддитивное выражение + мультипликативное-выражение
аддитивное-выражение - мультипликативное-выражение

мультипликативное-выражение:
выражение-pm
мультипликативное-выражение * выражение-pm
мультипликативное-выражение / выражение-pm
мультипликативное-выражение % выражение-pm

выражение-pm:
выражение-приведения
выражение-pm .* выражение-приведения
выражение-pm ->* выражение-приведения

выражение-приведения:
унарное-выражение
( имя-типа ) выражение-приведения

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

унарная-операция: один из
* & + - ! ~

выражение-размещения:
::opt new параметры-new opt имя-типа-new инициализатор-new
::opt new параметры-new opt ( имя-типа ) инициализатор-new

параметры-new:
( список-выражений )

имя-типа-new:
список-спецификаций-типа описатель-new opt

описатель-new:
* список-спецификаций-cv opt описатель-new opt
имя-класса :: список-спецификаций-cv opt описатель-new opt
описатель-new opt [ выражение ]

инициализатор-new:
( список-инициализаторов opt )

выражение-освобождения:
::opt delete выражение-приведения
::opt delete [] выражение-приведения

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

список-выражений:
выражение-присваивания
список-выражений , выражение-присваивания

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

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

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

литерал:
целая константа
символьная константа
константа с плавающей точкой
строка литералов

    R.17.3 Описания



описания:
спецификации-описания opt список-описателей opt ;
описание-asm
определение-функции
спецификация-связи

спецификация-описания:
спецификация-класса-памяти
спецификация-типа
спецификация-fct
спецификация-шаблона-типа
friend
typedef

спецификации-описания:
спецификации-описания opt спецификация-описания

спецификация-класса-памяти:
auto
register
static
extern

спецификация-fct:
inline
virtual

спецификация-типа:
имя-простого-типа
спецификация-класса
спецификация-перечисления
спецификация-сложного-типа
:: имя-класса
const
volatile

имя-простого-типа:
полное-имя-класса
уточненное-имя-типа
char
short
int
long
signed
unsigned
float
double
void

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

служебное-слово-класса:
class
struct
union

уточненное-имя-типа:
имя-typedef
имя-класса :: уточненное-имя-типа

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

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

имя-перечисления:
идентификатор

спецификация-перечисления:
enum идентификатор opt { список-перечисления }

список-перечисления:
элемент-перечисления
список-перечисления , элемент-перечисления

элемент-перечисления:
идентификатор
идентификатор = выражение-константа

спецификация-связи:
extern строка-литерал { список-описаний opt }
extern строка-литерал описание

список-описаний:
описание
список-описаний описание

описание-asm:
asm ( строка-литерал) ;

    R.17.4 Описатели



список-описаний:
описатель-с-инициализатором
список-описаний , описатель-с-инициализатором

описатель-с-инициализатором:
описатель инициализатор opt

описатель:
имя-в-описателе
операция-ptr описатель
описатель (список-описаний-параметров) список-спецификаций-cv opt
описатель [ выражение-константа opt]
( описатель )

операция-ptr:
* список-спецификаций-cv opt
& список-спецификаций-cv opt
полное-имя-класса :: * список-спецификаций-cv opt

список-спецификаций-cv:
const
volatile

имя-в-описателе:
имя
имя-класса
~имя-класса
имя-typedef
уточненное-имя-типа

имя-типа:
список-спецификаций-типа абстрактный-описатель opt

список-спецификаций-типа:
спецификация-типа список-спецификаций-типа

абстрактный-описатель:
операция-ptr абстрактный-описатель opt
абстрактный-описатель opt ( список-описаний-параметров ) список-спецификаций_cv opt
абстрактный-описатель opt [ выражение-константа opt ]
( абстрактный-описатель )

список-описаний-параметров:
список-описаний-парам opt ... opt
список-описаний-парам , ...

список-описаний-парам:
описание-параметра
список-описаний-парам , описание-параметра

описание-параметра:
спецификации-описания описатель
спецификации-описания описатель = выражение
спецификации-описания абстрактный-описатель opt
спецификации-описания абстрактный-описатель opt = выражение

определение-функции:
спецификации-описания opt описатель инициализатор-ctor тело-функции

тело-функции:
составной-оператор

инициализатор:
= выражение-присваивания
= { список-инициализаторов , opt }
( список-выражений )

список-инициализаторов:
выражение-присваивания
список-инициализаторов , выражение-присваивания
{ список-инициализаторов , opt }

    R.17.5 Описания класса



спецификация-класса:
заголовок-класса { список-членов opt }

заголовок-класса:
служебное-слово-класса идентификатор opt спец-базовых opt
служебное-слово-класса имя-класса спец-базовых opt

служебное-слово-класса:
class
struct
union

список-членов:
описание-члена список-членов opt
спецификация-доступа : список-членов opt

описание-члена:
спецификации-описания opt список-описателей-членов opt ;
определение-функции ; opt
уточненное-имя ;

список-описателей-членов:
описатель-члена
список-описателей-членов , описатель-члена

описатель-члена:
описатель спецификация-чистой opt
идентификатор opt : выражение-константа

спецификация-чистой:
= 0

список-базовых:
спецификация-базовых
список-базовых , спецификация-базовых

спецификация-базовых:
полное-имя-класса
virtual спецификация-доступа opt полное-имя-класса
спецификация-доступа virtual opt полное-имя-класса

спецификация-доступа:
private
protected
public

имя-функции-преобразования:
operator имя-типа-преобразования

имя-типа-преобразования:
список-спецификаций-типа операция-ptr opt

инициализатор-ctor:
: список-инициализаторов-членов

список-инициализаторов-членов:
инициализатор-члена
инициализатор-члена , список-инициализаторов-члена

инициализатор-члена:
полное-имя-класса ( список-выражений opt )
идентификатор

имя-функции-оператор:
operator операция

операция: один из
new delete
+ - * / % ^ & | ~
! = < > += -= *= /= %=
^= &= |= << >> >>= <<= == !=
<= >= && || ++ -- , ->* ->
() []

    R.17.6 Операторы



оператор:
помеченный-оператор
оператор-выражение
составной-оператор
выбирающий-оператор
оператор-цикла
оператор-перехода
оператор-описания

помеченный-оператор:
идентификатор : оператор
case выражение-константа : оператор
default : оператор

оператор-выражение:
выражение opt ;

составной-оператор:
{ список-операторов opt }

список-операторов:
оператор
список-операторов оператор

выбирающий-оператор:
if ( выражение ) оператор
if ( выражение ) оператор else оператор
switch ( выражение ) оператор

оператор-цикла:
while ( выражение ) оператор
do оператор while (выражение)
for ( оператор-иниц выражение opt ; выражение opt ) оператор

оператор-иниц:
оператор-выражение
оператор-описание

оператор-перехода:
break ;
continue ;
return выражение opt ;
goto идентификатор ;

оператор-описания:
описание

    R.17.7 Препроцессор



#define идентификатор строка-лексем
#define идентификатор ( идентификатор , ... , идентификатор ) строка-лексем

#include "имяфайла"
#include <имяфайла>

#line константа "имяфайла" opt
#undef идентификатор

условное:
часть-if части-elif opt часть-else opt строка-endif

часть-if:
строка-if текст

строка-if:
# if выражение-константа
# ifdef идентификатор
# ifndef идентификатор

части-elif:
строка-elif текст
части-elif строка-elif текст

строка-elif:
# elif выражение-константа

часть-else:
строка-else текст

строка-else:
# else

строка-endif:
# endif

    R.17.8 Шаблоны типа



описание-шаблона-типа:
template < список-параметров-шаблона-типа> описание

список-параметров-шаблона-типа:
параметр-шаблона-типа
список-параметров-шаблона-типа , параметр-шаблона-типа

параметр-шаблона-типа:
параметр-типа
описание-параметра

параметр-типа:
class идентификатор

имя-шаблонного-класса:
имя-шаблона-типа < список-парам-шаблона-типа >

список-парам-шаблона-типа:
парам-шаблона-типа
список-парам-шаблона-типа , парам-шаблона-типа

парам-шаблона:
выражение
имя-типа

    R.17.9 Обработка особых ситуаций



проверяемый-блок:
try составной-оператор список-обработчиков

список-обработчиков:
обработчик список-обработчиков opt

обработчик:
catch ( описание-особой-ситуации ) составной-оператор

описание-особой-ситуации:
список-спецификаций-типа описатель
список-спецификаций-типа абстрактный-описатель
список-спецификаций-типа
...

выражение-запуска:
throw выражение opt

спецификация-особой-ситуации:
throw ( список-типа opt )

список-типа:
имя-типа
список-типа , имя-типа

    R.18 Приложение B: Совместимость



Это приложение не относится к справочному руководству С++ и не
является определением конструкций языка.
Язык С++ основывается на С (описание в книге Кернигана и Ритчи,
78 г., дальше K&R) и включает большинство изменений, предложенных
в ANSI стандарте для С. При конвертировании программ на языках
С++, K&R C и ANSI C могут возникнуть трудности в связи с различным
вычислением в них выражений. Транслятор должен распознавать все различия
между С++ и ANSI C. Программы на С++ и ANSI C должны иметь одинаковый
смысл за исключением трех следующих случаев:
В языке С выражение sizeof('a') равно sizeof(int), а в С++
оно равно sizeof(char).
Если есть описание

enum e { A };

то sizeof(A) равно в С sizeof(int), тогда как в С++ оно равно sizeof(e)
и не обязано быть равно sizeof(int).
Имя структуры, описанной во внутреннем блоке, может скрывать имя
объекта, функции, элемента перечисления или типа из внешнего блока.
Приведем пример:

int x[99];
void f()
{
struct x { int a; };
sizeof(x); /* для C это размер массива */
/* а для C++ размер структуры */
}

    R.18.1 Расширения



В этом разделе перечисляются основные расширения языка С, введенные
в С++.

    R.18.1.1 Возможности С++, введенные в 1985 г.



Здесь перечисляются возможности, добавленные к С, версией языка
С++ 1985 г.
Можно указывать типы формальных параметров функции ($$R.8.2.5), и они
будут проверяться ($$R.5.2.2). Будет происходить преобразование
типа ($$R.5.2.2). Это есть и в ANSI C.
В выражениях со значениями типа float вычисления могут проходить
с обычной точностью ($$R.3.6.1 и $$R.4.3). Это есть и в ANSI C.
Можно перегружать имена функций; $$R.13.
Можно перегружать операции; $$R.13.4
Возможна реализация вызова функций подстановкой; $$R.7.1.2.
Можно описывать объекты, представляющие данные, со спецификацией
const; $$R.7.1.6. Это есть и в ANSI C.
Можно описывать типа ссылки; $$R.8.2.2 и $$R.8.4.3.
Возможно управление свободной памятью с помощью операций new и
delete; $$R.5.3.3 и $$R.5.3.4.
Введены классы, которые позволяют: скрывать информацию ($$R.11),
проводить инициализацию ($$R.12.1), осуществлять пользовательские
преобразования типа ($$R.12.3) и работать с динамическими типами
с помощью виртуальных функций ($$R.10.2).
Имя класса или перечисления считается именем типа; $$R.9.
Указатель на любой объект c типом, не являющимся const или volatile,
можно присвоить указателю типа void*. Это есть и в ANSI C.
Указатель на функцию можно присваивать указателю типа void*;
$$R.4.6.
Описание внутри блока считается оператором; $$R.6.7.
Можно описывать безымянные объединения; $$R.9.5.

    R.18.1.2 Возможности, добавленные в С++ после 1985 г.



Здесь перечисляются основные расширения С++ после 1985 г.:
Класс может иметь более одного прямого базового класса
(множественное наследование); $$R.10.1.
Члены класса могут быть защищенными; $$R.11.
Операции new и delete можно описывать в классе и перегружать;
$$r.5.3.3, $$R.5.3.4, $$R.12.5. Это позволило определенный способ
управления памятью для класса с помощью "присваивания указателю
this" отнести в раздел анахронизмов; $$R.18.3.3.
Можно явно уничтожать объекты; $$R.12.4.
Присваивания и инициализация для класса определены как присваивание и
инициализация по членам; $$R.12.8.
Служебное слово overload стало излишним и отнесено к разделу
анахронизмов; $$R.18.3.
Произвольные выражения разрешены в качестве инициализаторов статических
объектов; $$R.8.4.