(см. $$R.11.4).

    R.7.1.6 Спецификация типа



К спецификации типа относятся:

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

При описании объекта служебные слова const и volatile можно добавить
к любой законной спецификации-типа. Во всех других случаях в описании
может присутствовать не более одной спецификации-типа. Объект со
спецификацией const можно инициализировать, но его значение не
должно изменяться в дальнейшем. Объект со спецификацией const, если
только он не был явно описан как extern, не подлежит внешнему
связыванию и должен инициализироваться ($$R.8.4, $$R.12.1). Целое
со спецификацией const, инициализированное выражением-константой,
может использоваться в выражении-константе ($$R.5.19). Каждый
элемент массива со спецификацией const имеет ту же спецификацию,
а каждый нестатический член, не являющийся функцией, из объекта класса
со спецификацией const сам считается const ($$R.9.3.1). Объект типа
без конструктора или деструктора, который имеет спецификацию const,
может быть помещен в память, доступную только по чтению. Попытка
записи в любую часть такого объекта или приведет к особой адресной
ситуации, или пройдет бесследно, как если бы объект не имел
спецификации const.
Не существует не зависящего от реализации объяснения объектов со
спецификацией volatile. Она служит подсказкой транслятору избегать
слишком активной оптимизации, связанной с этим объектом, поскольку
значение объекта может изменяться способами, скрытыми от
транслятора. Каждый элемент массива со спецификацией volatile
имеет ту же спецификацию и каждый нестатический член, не являющийся
функцией, из объекта класса со спецификацией volatile сам считается
volatile ($$R.9.3.1).
Если спецификация-типа отсутствует в описании, она считается
заданной как int.

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

Вместе с int нельзя задавать более одного служебного слова long
или short. Они могут использоваться и поодиночке, тогда считается,
что тип есть int. Служебное слово long может появиться вместе с
double. Вместе с char, short, int или long нельзя задавать более
одного служебного слова signed или unsigned. Они могут
использоваться и поодиночке, тогда считается, что тип есть int.
Спецификация signed указывает, что объекты типа char и битовые
поля являются знаковыми, для других целочисленных типов эта
спецификация избыточна.
Конструкции спецификация-класса и спецификация-перечисления
определяются в $$R.9 и $$R.7.2 соответственно.

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

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

Если задан идентификатор, спецификация-сложного-типа описывает
его как имя-класса (см. $$R.9.1).
Если определено имя, которое описывается с помощью спецификации
union, то оно должно быть определено как объединение. Если определено
имя, которое описывается с помощью спецификации class, то оно должно
быть определено с помощью спецификаций class или struct. Если
определено имя, которое описывается с помощью спецификации struct,
оно должно быть определено с помощью спецификации class или
struct. Имена вложенных типов ($$R.9.7) должны уточняться именем
объемлющего класса:

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

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

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

Имя, уточненное именем-класса должно быть типом, определенным в
этом классе или в базовом классе этого класса. Как обычно, имя,
описанное в производном классе, делает невидимыми члены с этим
именем из базовых классов (см. $$R.3.2).

    R.7.2 Описание перечисления



Перечисление является отдельным целочисленным типом ($$R.3.6.1)
с константами-именами. Его имя в своей области видимости становится
конструкцией имя-перечисления, т.е. служит зарезервированным словом.

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

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

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

элемент-перечисления:
идентификатор
идентификатор = выражение-константа
Все идентификаторы из списка-перечисления считаются описанными
как константы и могут появляться всюду, где требуются константы.
Если не было элементов перечисления с =, то значения констант
начинаются с нуля и последовательно увеличиваются на единицу
по мере продвижения в списке слева направо. Если элемент
перечисления встретился с =, то его идентификатор принимает заданное
значение, а последующие идентификаторы без инициализирующей части
будут получать возрастающие значения, начиная с заданного. Значение
элемента перечисления должно быть типа int или значением, которое
можно привести к int с помощью стандартных целочисленных
преобразований ($$R.4.1).
Имена элементов перечисления должны быть отличны от имен обычных
переменных и других элементов перечисления той же области
видимости. Значения элементов перечисления не обязаны отличаться
друг от друга. Считается, что элемент перечисления описан с момента
появления его идентификатора или инициализирующего значения,
(если оно есть). Например, в определениях

enum { a, b, c=0 };
enum { d, e, f=e+2 };

значения a, c, и d заданы как 0, b и e как 1, а f как 3.
Каждое перечисление является целочисленным типом, который
отличен от всех других целочисленных типов. Типом элемента перечисления
считается данное перечисление. Значение элемента перечисления или
объекта типа перечисления преобразуется к целому с помощью
стандартных целочисленных преобразований ($$R.4.1). Например,
в следующем фрагменте:

enum color { red, yellow, green=20, blue };
color col = red;
color* cp = &col;
if (*cp == blue ) // ...

color задан как целочисленный тип, описывающий разные цвета,
col описан как объект этого типа, а cp как указатель на объект
этого типа. Возможными значениями объекта типа color являются
red, yellow, green, blue. Эти значения можно преобразовать
в целые значения 0, 1, 20 и 21. Поскольку каждое перечисление - это
отдельный тип, объекту типа color можно присваивать только значения
типа color, например,

color c = 1; // ошибка: несоответствие типов
// нет преобразования от int в color

int i = yellow; // нормально: yellow преобразуется в int со значением 1
// стандартное целочисленное преобразование

Обратитесь также к $$R.18.3.
Элементы перечисления, определенные в классе ($$R.9), относятся
к области видимости этого класса, и к ним можно обращаться извне
функций-членов этого класса только с помощью явного уточнения
именем класса ($$R.5.1). Имя самого типа перечисления локально
в этом классе ($$R.9.7), например,

class X {
public:
enum direction { left='l', right='r' };
int f(int i)
{ return i==left ? 0 : i==right ? 1 : 2; }
};

void g(X* p)
{
direction d; // ошибка: `direction' вне
int i; // области видимости
i = p->f(left); // ошибка: `left' тоже невидим
i = p->f(X::right); // нормально
// ...
}

    R.7.3 Описания asm



Описание asm имеет вид:

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

Назначение описания asm определяется реализацией. Обычно оно
используется для передачи информации от транслятора к ассемблеру.

    R.7.4 Спецификации связи



С помощью спецификации-связи можно связать ($$R.3.3) фрагменты
программ на С++ и на другом языке:

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

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

Требуемое связывание задается с помощью строки-литерала. Ее назначение
определяется реализацией. Но во всех реализациях должно быть
предусмотрено связывание с функцией на языке С ("С") и с функцией
на языке С++ ("С++"). По умолчанию связывание задается как "С++",
например,

complex sqrt(complex); // по умолчанию связывание с C++
extern "C" {
double sqrt(double); // связывание с C
}

Спецификации связи могут быть вложенными. Спецификация связи
не задает область видимости. Спецификация-связи может встретиться
только в файловой области видимости ($$R.3.2). Спецификация-связи
для класса относится к объектам, описанным в нем, и функциям, не
являющимся членами. Спецификация-связи, относящаяся к некоторой
функции, относится и ко всем объектам и функциям, описанным в ней.
Описание связи, содержащее неизвестную для реализации строку,
считается ошибочным.
Если функция имеет более одной спецификации-связи, то они должны
быть согласованы, т.е. задавать одну и ту же строку-литерал.
Описание функции без указания спецификации-связи не должно
предшествовать первому указанию спецификации связи для этой функции.
Функция может быть описана без указания спецификации связи даже
после явного указания спецификации связи, но связывание, явно заданное
в более раннем описании, не будет устранено таким описанием функции.
Из множества перегруженных функций ($$R.13) с данным именем
не более одной может иметь связывание с языком С, см. $$R.7.4.
Связывание можно установить для объектов, например:

extern "C" {
// ...
_iobuf_iob[_NFILE];
// ...
int _flsbuf(unsigned,_iobuf*);
// ...
}

Когда задается спецификация связи, то функции и объекты можно описать как
статические внутри { }. Для таких функций или объектов команда
связывания игнорируется. Иначе, функция, описанная при задании связи,
трактуется, как если бы она была явно описана как extern, например,
ниже второе описание ошибочно ($$R.7.1.1):

extern "C" double f();
static double f(); // ошибка

Объект, описанный внутри конструкции

extern "C" { /* ... */ }

все же считается определенным, а не просто описанным.
Связывание объектов на С++ с объектами, определенными на других
языках, так же как и обратное связывание, зависит от языков и
реализации. Такое связывание возможно только в том случае, когда
алгоритмы размещения объектов в памяти являются достаточно схожими
для двух языков.
Если для задания связи в строке-литерале из спецификации-связи
используется имя языка программирования, то рекомендуется, чтобы
написание этого имени копировалось из документа, определяющего данный
язык, например, Ada (а не ADA) и Fortran (а не FORTRAN).

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



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

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

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

Описание состоит из двух частей: спецификации (спецификация-описания;
см. $$R.7.1) и описателей (список-описателей). Спецификации задают
основной тип, класс памяти или другие свойства описываемых объектов
и функций. Описатели задают имя этих объектов и функций, а также,
возможно, изменяют тип с помощью таких операций, как * (указатель на)
и () (функция возвращающая). В описателе также можно задать начальные
значения, инициализация обсуждается в $$R.8.4 и $$R.12.6.
Описатели имеют такой синтаксис:

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

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

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

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

Конструкция имя-класса имеет определенное назначение при описании
класса с этим именем, она же используется как уточнение в операции ::
для разрешения коллизий в области видимости ($$R.12.1, $$R.12.4).

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



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

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

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

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

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

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

int // int i
int * // int *pi
int *[3] // int *p[3]
int (*)[3] // int (*p3i)[3]
int *() // int *f()
int (*)(double) // int (*pf)(double)

задают соответственно такие типы: "целое", "указатель на целое",
"массив из 3 указателей на целое", "указатель на массив из 3 целых",
"функция без параметров, возвращающая указатель на целое",
"указатель на функцию с параметром типа double, возвращающую целое".

    R.8.1.1 Устранение неоднозначности



Неоднозначность, отмеченная в $$R.6.8, которая возникает из-за сходства
между приведением, заданным в функциональном стиле, и описанием,
может также появиться в контексте описания. В этом контексте она
проявляется как сходство между описанием функции, в котором есть
избыточные скобки вокруг имени параметра, и описанием объекта, в
котором в качестве инициализатора используется операция приведения,
заданная в функциональном стиле. Как и для операторов, неоднозначность
устраняется правилом, согласно которому следует считать описанием любую
конструкцию, которая может служить таковым. Можно явно устранить
неоднозначность в описании или с помощью приведения, заданного не в
функциональном стиле, или с помощью операции = для обозначения
инициализации, например,

struct S {
S(int);
};

void foo(double a)
{
S x(int(a)); // описание функции
S y((int)a); // описание объекта
S z = int(a); // описание объекта
}

    R.8.2 Смысл описателей



Список описателей следует после (возможно пустого) списка
спецификаций-описания ($$R.7.1). Каждый описатель содержит в точности
одно имя-из-описателя, которое задает описываемый идентификатор.
Если не считать описаний некоторых специальных функций ($$R.12.3,
$$R.13.4), имя-из-описателя является просто идентификатором.
Спецификации auto, static, extern, register, friend, inline, virtual
или typedef относятся непосредственно к каждому имени-из-описателя из
списка описателей. Тип каждого имени-из-описателя определяется как
спецификацией-описания ($$R.7.1), так и его описателем.
Таким образом, описание некоторого идентификатора имеет вид

T D

где T обозначает тип, а D - описатель. Если в описании D есть
идентификатор без скобок, то тип этого идентификатора есть T.
В описании, где D имеет вид

( D1 )

тип D1 такой же, как и тип D. Наличие скобок не меняет типа заключенного
в них имени-из-описателя, но для сложных описателей оно может повлиять
на порядок применения операций.

    R.8.2.1 Указатели



В описании T D, в котором D имеет вид

* список-спецификаций-cv opt D1

тип описываемого идентификатора есть
"... список-спецификаций-cv указатель на T". Конструкция
список-спецификаций-cv относится к указателю, а не к указуемому
объекту.
Например, в описаниях

const ci = 10, *pc = &ci, *const cpc = pc;
int i *p, *const cp = &i;

определяются: ci как константа целое; pc как указатель на константу
целое; cpc как константа указатель на константу целое; i как целое;
p как указатель на целое; и cp как константа указатель на целое.
После инициализации значения ci, cpc и cp не могут быть изменены.
Значение pc можно изменять так же, как и значение объекта, на который
указывает cp. Приведем примеры допустимых операций:

i = ci;
*cp = ci;
pc++;
pc = cpc;
pc = p;

Недопустимы следующие операции:

ci = 1; // ошибка
ci++; // ошибка
*pc = 2; // ошибка
cp = &ci; // ошибка
cpc++; // ошибка
p = pc; // ошибка

Каждая из этих операций недопустима или потому, что она изменяет значение
объекта, описанного со спецификацией const, или потому, что делает
такое изменение возможным позднее с помощью указателя, настроенного
на объект без спецификации const.
Аналогична ситуация со спецификацией volatile.
Обратитесь к $$R.5.17 и $$R.8.4.
Нельзя описывать указатели на ссылки ($$R.8.2.2) или указатели
на битовые поля ($$R.9.6).

    R.8.2.2 Ссылки



В описании T D, в котором D имеет вид

& список-спецификаций-cv opt D1

тип описываемого идентификатора есть
"...список-спецификаций-cv ссылка на T". Тип void& недопустим.
Например, во фрагменте

void f(double& a) { a += 3.14; }
// ...
double d = 0;
f(d);

a описывается как параметр, являющийся ссылкой, поэтому вызов
f(d) приведет к увеличению d на 3.14. Во фрагменте

int v[20];
// ...
int& g(int i) { return v[i]; }
// ...
g(3) = 7;

описывается: функция g() возвращает ссылку на целое; поэтому
оператор g() = 7; присвоит 7 четвертому элементу массива v.
Рассмотрим следующий программный фрагмент:

struct link {
link* next;
};
link* first;

void h(link*& p) // `p' ссылка на указатель
{
p->next = first;
first = p;
p = 0;
}

void k()
{
link* q = new link;
h(q);
}

Здесь p описано как ссылка на указатель на link, поэтому вызов h(q)
не изменит значение q, равное 0, см. также $$R.8.4.3.
Недопустимы ссылки на ссылки, ссылки на битовые поля ($$R.9.6),
массивы ссылок и указатели на ссылки. Описание ссылки должно содержать
инициализатор ($$R.8.4.3), за исключением тех случаев, когда описание
содержит явную спецификацию extern ($$R.7.1.1), или является описанием
члена класса ($$R.9.2) при описании самого класса, или является
описанием параметра или возвращаемого типа ($$R.8.2.5),
см. также $$R.3.1.

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



В описании T D, в котором D имеет вид
полное-имя-класса :: * список-спецификаций-cv opt D1
тип описываемого идентификатора есть
"... список-спецификаций-cv указатель на член класса полное-имя-класса типа T".
Например, во фрагменте

class X {
public:
void f(int);
int a;
};

int X::* pmi = &X::a;
void (X::* pmf)(int) = &X::f;

pmi и pmf описываются как указатель на член X типа T и указатель на
член X типа void(int) соответственно. Эти объекты можно использовать
так:

X obj;
// ...
obj.*pmi = 7; // присвоить 7 члену obj типа int
(obj.*pmf)(7); // вызвать функцию-член obj
// с параметром 7

Отметим, что указатель на член нельзя настроить на статический
член класса ($$R.9.4), см. также $$R.5.5 и $$R.5.3.

    R.8.2.4 Массивы



В описании T D, в котором D имеет вид

D1 [ выражение-константа opt ]

описывается идентификатор типа " ... массив T". Если
выражение-константа присутствует ($$R.5.19), то оно должно иметь
целочисленный тип и значение, большее 0. Это выражение задает число
элементов массива. Если значение выражения-константы есть N, то
массив имеет N элементов с индексами от 0 до N-1.
Массив можно образовывать из: одного из основных типов (за исключением
void), указателя, указателя на члены, класса, перечисления или из
другого массива.
Если подряд идут несколько спецификаций "массив ...", образуется
многомерный массив, причем выражение-константа, задающее границы
массива, может отсутствовать только для первого массива. Такое умолчание
полезно в случае параметров функции типа массив, а также когда массив
является внешним, а его определение, с которым связано резервирование
памяти, находится в другом месте. Первое выражение-константа может
быть пропущено и в том случае, если за описателем следует
список-инициализаторов ($$R.8.4). Тогда размер массива определяется
числом элементов, приведенных в инициализаторе ($$R.8.4.1).
В описании

float fa[17], *afp[17];

описаны массив чисел типа float и массив указателей на числа типа float,
а в описании

static int x3d[3][5][7];

описан статический трехмерный массив целых размера 3x5x7. Строго
говоря, x3d является массивом из трех элементов, каждый из которых
есть массив из пяти массивов, а каждый из последних является массивом
из семи целых. В выражении допустимо появление любого из следующих
выражений: x3d, x3d[i], x3d[i][j], x3d[i][j][k].
Если в выражении участвует идентификатор типа массив, то, исключая
случаи операнда в операциях sizeof или & и инициализатора для
ссылки ($$R.8.4.3), его тип преобразуется в указатель на первый
элемент массива. Несмотря на это преобразование, массивы не являются
изменяемыми адресами. Если не считать случай использования массива
при описании класса ($$R.13.4.5), операция индексации определяется
так, что E1[E2] совпадает с *((E1) + (E2)). С учетом правил
преобразования типов для операции +, если E1 есть массив, а E2
целое, то E1[E2] указывает на E2-элемент из E1. Поэтому, несмотря
на свой асиметричный вид, индексация - коммутативная операция.
Аналогичное правило действует и для многомерных массивов. Если
E - n-мерный массив размера ixjx...xk, то в выражении он
преобразуется в указатель на (n-1)-мерный массив размера jx...xk.
Если к этому указателю явно или неявно в результате индексации применяется
операция *, указуемый (n-1)-мерный массив сам немедленно преобразуется
в указатель.
Например, рассмотрим описание

int x[3][5];

Здесь описан массив из 3x5 целых. Если в выражении появляется x, то
оно преобразуется в указатель на первый массив из пяти целых.
Если в выражении появляется x[i], что эквивалентно *(x+i), в начале
x преобразуется в указатель, как было сказано выше, затем x+i
преобразуется к типу x, для чего необходимо i умножить на размер объекта,
на который указывает x, т.е. на размер пяти целых. Затем происходит
сложение и применяется косвенность, после чего получим массив (из пяти
целых), который в свою очередь преобразуется в указатель на первое из
целых. Если есть еще одна индексация, процесс повторяется, и на этот раз
мы получим в результате целое.
Из всего этого следует, что массивы В С++ хранятся по строкам
(последний индекс изменяется быстрее всего), а значение первого
индекса из описания позволяет вычислить размер памяти, необходимой
для массива, однако при вычислении индексного выражения первый индекс
роли не играет.

    R.8.2.5 Функции



В описании T D, в котором D имеет вид

D1 (список-описаний-параметров ) список-спецификаций-cv opt

описываемый идентификатор имеет тип
"...список-спецификаций-cv функция с параметрами типа
список-описаний-параметров возвращающая T".

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

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

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

Если список-описаний-параметров завершается эллипсисом (...),
про число параметров известно только то, что оно больше или равно
числа заданных параметров, если список параметров пуст, то функция
параметров не имеет. Список параметров void эквивалентен пустому
списку параметров. Не считая этого случая, void не может быть типом
параметра (хотя типы, получаемые из void, такие как void*, допустимы).


    R.8.3 Определения функций



Определения функций имеют вид

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

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

Конструкция описатель из определения-функции должна содержать описатель
вида

D1 ( список-описаний-параметров ) список-спецификаций-cv opt

в соответствии с определениями из $$R.8.2.5
Формальные параметры относятся к области видимости самого
большого блока тела-функции.
Приведем пример полного определения функции.

int max( int a, int b, int c)
{
int m = (a > b) ? a : b;
return (m > c) ? m : c;
}

Здесь int представляет спецификации-описания, max(int a, int b, int c)
- описатель, а { /* ... */ } - тело-функции.
Конструкция инициализатор-ctor используется только в конструкторах,
см. $$R.9.3.1 и $$R.12.6.
Конструкция список-спецификаций-cv может участвовать:
в описании нестатической функции-члена, в определении нестатической
функции-члена или в описании указателя на функцию-член, см. $$R.9.3.1.
Она относится к типу функции.
Отметим, что неиспользуемым формальным параметрам имена можно
не давать, например,

void print(int a, int)
{
printf("a = %d\n",a);
}

    R.8.4 Инициализаторы



За описателем может идти начальное значение описываемого идентификатора.

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

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

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

int f(int);
int a = 2;
int b = f(a);
int c(b);

Указатель типа const T*, т.е. указатель на константу T, может
инициализироваться указателем типа T*, но инициализация для указателей
в обратном порядке незаконна. Объекты типа T можно инициализировать
объектами типа T независимо от использования спецификаций const или
volatile в типах инициализируемой переменной или инициализатора,
например,

int a;
const int b = a;
int c = b;

const int* p0 = &a;
const int* p1 = &b;
int* p2 = &b; // ошибка: указатель без const
// настраивается на объект const
int *const p3 = p2;
int *const p4 = p1; // ошибка: указатель без const
// настраивается на объект const
const int* p5 = p1;

Здесь причина обеих ошибок одна: если допустить подобную инициализацию,
она позволит изменять с помощью указателя без соответствующей
спецификации значение чего-то, что было описано как const.
На выражения для стандартных значений параметров накладывается
больше ограничений, см. $$R.8.2.6.
Инициализация объектов классов с помощью конструкторов описывается
в $$R.12.6.1. Копирование объектов классов описывается в $$R.12.8.