C++11

[մինի|[Բյորն Ստրաուստրուպը C++ ծրագրավորման լեզվի ստեղծողը]]

**C++11**-ը C++ ծրագրավորման լեզվի ստանդարտի տարբերակ է։ Այն Միջազգային ստանդարտացման կազմակերպության (ISO) կողմից հաստատվել է 2011 թվականի օգոստոսի 12-ին՝ փոխարինելով C++03 ստանդարտը և նախորդելով 2014 թ․ օգոստոսի 18-ին հաստատված C++14 ստանդարտին։ Այս ստանդարտների անունները կառուցված են անվան մեջ ստանդարտացման տարեթիվը նշելու սկզբունքով, չնայած այն ավելի վաղ հայտնի էր **[[C++]]0x** անունով, քանի որ դրա հրապարակումը ակնկալվում էր մինչև 2010 թվականը։

Չնայած այն բանին, որ նախագծման նպատակներից էր լեզվի միջուկում փոփոխություններ կատարելու փոխարեն նախապատվությունը տալ գրադարաններում կատարվող փոփոխություններին, C++11 տարբերակում որոշ փոփոխություններ են կատարվել նաև լեզվի միջուկում։ Լեզվի միջուկում զգալի փոփոխություններ են կրել բազմահոսք ծրագրավորման, ընդհանրացված ծրագրավորման, միաձև արժեքավորման հնարավորությունները, ինչպես նաև արտադրողականությունը։ Զգալի փոփոխություններ են կատարվել նաև C++ լեզվի ստանդարտ գրադարանում (STL)։

## Ստանդարտի առաջարկվող փոփոխությունները
Ինչպես արդեն նշվել է, փոփոխությունները վերաբերում են ինչպես **[[C++]]**-ի միջուկին, այնպես էլ ստանդարտ գրադարանին։

Ապագա ստանդարտի ամեն հատվածը մշակելիս հանձնաժողովը օգտագործել է մի քանի սկզբունքներ.

* Լեզվի կայունության աջակցում և համատեղելիության ապահովումը **[[C++98]]** ստանդարտի հետ, հնարավորության դեպքում նաև **[[C]]**-ի հետ
* Նոր հնարավորությունները ավելացնել ստանդարտ գրադարանի ` ոչ թե միջուկի միջոցով
* Նախընտրել այն փոփոխությունները, որոնք լավացնում են ծրագրավորելու հմտությունները(տեխնիկան)
* Կատարելագործել **[[C++]]**-ը համակարգի և գրադարանային դիզայնի տեսանկյունից, նոր հանրավորություններ, օգտակար և առանձին ծրագրերի փոխարեն

լավացնել տիպերի ահահովությունը և ապահովել այլընտրանքային ապահովություն վտանգավոր մոտեցումների ժամանակ

* Բարձրացնել արտադրողականությունը և անմիջապես սարքավորման հետ աշխատելու հնարավորությունը, ապահովել իրական՝ շատ տարածված խնդիրների լուծումը.

իրագործել «Չես վճարում նրա համար ինչ չես օգտագործում» սկզբունքը

* Դարձնել **[[C++]]**-ը հեշտ սովորելու համար, առանց ծրագրավորողների հնարավորությունները քչացնելու

Ուշադրություն է դարձվել սկսնակներին, ովքեր ծրագրավորողների մեծ մասն են կազմում։ Շատ սկսնակներ չեն ձգտում խորացնել **[[C++]]**-ի գիտելիքները, սահմանափակվելով օգտագործումը նեղ մասնագիտական խնդիրներ լուծելով։ Բացի այդ հաշվի առնել **C++**-ի ունիվերսալությունը և օգտագործման բազմազանությունը, նույնիսկ հմուտ ծրագրավորողը կարող է հայտնվել սկսնակի դերում նոր ծրագրավորման մեթոդոլոգիա օգտագործելիս։

## Լեզվի միջուկի ընդլայնումը
Հանձնաժողովի առաջնային խնդիրն էր զարգացնել լեզվի միջուկը։ Միջուկը զգալիորեն բարելավել է, ավելացվել են բազմահոսքայնության և ընդհանուր ծրագրավորման հնարավորությունները։

Հարմարության համար միջուկի հնարավորությունները և նրա փոփոխությունները բաժանվել են երեք մասի. արտադրողականության բարձրացում, հարմարության լավացում և նոր հնարավորություններ։

### Հարմարության համար
Լեզվի այս բաղադրիչը ներմուծված է հիշողության ծախսի քչացման և արտադրողականության մեծացման համար։

#### Ժամանակավոր օբեկտների հղումներ և տեղափոխման սեմանտիկա
**[[C++]]** ի ստանդարտով ժամանակավոր օբեկտը, որը առաջացել է արտահայտության հաշվարկի ժամանակ, կարելի է փոխանցել ֆունկցիային, սակայն միայն հաստատուն(`const`) հղումով։ Ֆունկցիան ի վիճակի չէ որոշել, կարելի է արդյոք դիտարկել փոխանցված օբեկտը ժամանակավոր և փոփոխոթյունների ենթակա (հաստատուն(const) օբեկտը որը նույնպես կարելի է փոխանցել այդ հղումով, չի կարելի փոփոխվել (օրինական))։ Սա խնդիր չէ պարզ կառուցվածքների համար՝ ինչպիսին complex֊ն է, սակայն բարդ կառուցվածք ունեցող տիպերի համար, որոնց անհրաժեշտ է հիշողության հատկացում-ազատում, ժամանակավոր օբեկտների ոչնչացումը և հիմնականի ստեղծումը երկարատև է, այն դեպքում երբ կարելի է ուղղակի անմիջապես փոխանցել ցուցիչը։

**C++ 11** ում հայտնվել է հղման նոր տեսակ՝ *rvalue-հղում* (անգլ․ rvalue reference)։ Այն հայտարարվում է հետևյալ կերպ՝ `type &&`։ Վերբեռնման նոր օրենքները թույլ են տալիս օգտագործել տարբեր վերբեռնման ֆուկցիաներ ոչ հաստատուն ժամանակավոր օբյեկտներով, որոնք հայտարարված են rvalue տիպի, և այլ մնացած բոլոր օբեկտների համար։ Նշված նորամուծությունը թույլ է տալիս իրականացնել *տեղափոխման սեմանտիկան* (*Move semantics*)։

Օրինակ `std::vector` -ը հասարակ կազմ է C զանգվածի և փոփոխականի, որը պահպանում է իր չափը։ Ընդօրինակող կոնստրուկտորը (`copy constructor`) `std::vector::vector(const vector &x)` կստեղծի նոր զանգված և կկրկնօրինակի տվյալները։

Տեղափոխման կոնստրուկտորը (`move constructor`) `std::vector::vector(vector &&x)` կարող է ուղղակի փոխանակվել ցուցիչներով և երկարություն պարունակող փոփոխականներով։ Հայտարարման օրինակ է՝


```cpp
template class vector {
  vector (const vector &); // պատճենող կոնստրուկտոր (դանդաղ)
  vector (vector &&); // ժամանակավոր օբյեկտից տեղափոխող կոնստրուկտոր (արագ)
  vector & operator = (const vector &); // սովորական վերագրում (դանդաղ)
  vector & operator = (vector &&); // ժամանակավոր օբյեկտի տեղափոխում (արագ)
};
```


#### Ընդհանրացված հաստատուն արտահայտություններ
**[[C++]]** ում միշտ էլ եղել է հաստատուն արտահայտություն հասկացությունը։ Այսպիսով, 3+4 տեսքի արտահայտությունները միշտ վերադարձրել են նույն արդյունքը, առանց կողմնակի էֆեկտների։ Իրենք իրենցով հաստատուն արտահայտությունները կոմպիլյատորին տալիս են հնարավորություն հարմարավետ օպտիմիզացիաների։

Կոմպիլյատորները հաշվում են նման արտահայտությունների արդյունքը միայն կոմպիլիացիայի փուլում են պահում այն ծրագրում։ Այսպիսով, նմանատիպ արտահայտությունները հաշվում են մեկ անգամ։ Նաև կան դեպքեր, երբ լեզվի ստանդարտը պահանջում է հաստատուն արտահայտությունների օգտագործումը։

Այդպիսի օրինակ է արտաքին զանգվածի տարբերակումը կամ թվարկումները (`enum`)


```cpp
int GiveFive() {return 5;}

int some_value[GiveFive() + 7]; // 12 չափանի զանգվածի ստեղծում; արգելված է C++ -ում
```


Վերոհիշյալ կոդը արգելված է **[[C++]]** ում, քանի որ `GiveFive() + 7` պաշտոնապես կոմպիլացիայի փուլում չի հանդիսանում հաստատուն արտահայտություն։ կոմպիլատորին այդ պահին ուղակի հայտնի չէ, որ ֆունկցիան իրականում վերադարձնում է հաստատուն։Կոմպիլատորի անհանգստության պատճառ հանդիսանում է այն, որ ֆունկցիան կարող է ազդել գլոբալ փոփոխականի վրա, աշխատանքի ընթացքում կանչել այլ ոչ հաստատուն ֆունկցիա և այլն։

**C++11** ներմուծել է բանալի բառ `(keyword) constexpr`, որը թույլատրում է օգտագործողին երաշխավորել, որ կամ ֆունկցիան կամ օբեկտի Կոնստրուկտորը վերադարձնում է հաստատուն կոմպիլիացիայի ժամանակ։ Վերևի կոդը կարելի է գրել հետևյալ կերպ՝


```cpp
constexpr int GiveFive()
{
    return 5;
}

int some_value[GiveFive() + 7]; // 12 չափանի զանգվածի ստեղծում; թույլատրված է C++11 -ում
```


Այդպիսի բանալի բառը (Անգլերեն. keyword) թույլ է տալիս կոմպիլիատորին հասկանալ և համոզվել, որ `GiveFive` վերադարձնում է հաստատուն։ `constexpr` ի օգտագործումը առաջացնում է ֆունկցիայի աշխատանքի խիստ սահմանափակումներ.

1. այդպիսի ֆունկցիան պետք է վերադարձնի արժեք

2. ֆունկցիայի մարմինը պետք է երևա վերադարձվող արտահայտությունում

3. արտահայտությունը պետք է բաղկացած լինի հաստատուններից և կամ այլ `constexpr` ֆունկցիաների կանչերից

4. `constexpr` նշված ֆունկցիան չի կարող օգտագործվել մինչև տվյալ մասի կոմպիլացվելը

Ստանդարտի նախորդ տսրբերակում հաստատուն արտահայտություններում կարող էին օգտագործվել միայն ամբողջ տիպի կամ համարակալման (`enum`) տիպի փոփոխականներ։**C++ 11** ում այդ սահմանափակումը հանված է այն փոփոխականների համար, որոնց հայտարարումից առաջ դրված է `constexpr` բանալի բառը (keyword)։


```cpp
constexpr double accelerationOfGravity = 9.8;
constexpr double moonGravity = accelerationOfGravity / 6;
```


Այդպիսի փոփոխականները արդեն անուղղակի համարվում են նշված `const` բանալի բառով։ Նրանցում կարող են պարունակվել միայն հաստատուն արտահայտությունների արդյունքներ կամ դրանց կոնստրուկտորներ։

Օգտագործողի կողմից նշված տիպից հաստատուն արժեքի նախագծման անհրաժեշտության դեպքում, այդպիսի տիպերի կոնստրուկտորները կարող են ներկայացված լինել `constexpr` ի

օգնությամբ։ Հաստատուն արտահայտությունների կոնստրուկտորները նման են հաստատուն ֆունկցիաներին, և պետք է կոմպիլացված լինի մինչ կոմպիլիացիայի այդ փուլին հասնելը։ Այդպիսի կոնստրուկտորը պետք է լինի դատարկ, և սկզբնարժեքավորի(`initialize`) իր տիպի անդամներին միայն հաստատուններով։

#### Պարզ տվյալների սահմանման փոփոխություններ
Ստանդարդ C++-ում միայն որոշակի օրենքներն բավարարող կառուցվածքներն(`Struct`) են կարող համարվել պարզ տվյալների տիպ(`Plain Data Type (POD)`)։Գոյություն ունեն ծանրակշիռ պատճառներ սպասելու այդ օրենքների ընդլայմանը, այն պատճառով, որ ավելի մեծ քանակի տրպեր դիտարկվի պարզ (`POD`)։ Այդ օրենքներին բավարարող տիպերը կարող են օգտագործվել օբեկտային շերտի իրականացման մեջ **[[C]]** ի հետ համաձայնեցված(совместимого)։ սակայն **[[C++ 03]]**-ում այս օրենքների ցուցակը չափազանց խիստ է։

**C++ 11** ը կթուլացնի մի քանի օրենքներ, որոնք վերաբերվում են պարզ տվյալների

տիպի(`POD`) սահմանմանը։

Դասը դիտարկվում է որպես պարզ տվյալների տիպ (`POD`), եթե այն ՏՐԻՎԻԱԼ Է (`trivial`) ստանդարտ դասավորությամբ (`standard-layout`) և եթե նրա բոլոր ոչ ստատիկ անդամ-տվյալները նույնպես հանդիսանում են պարզ տվյալների

տիպի(`POD`) :

Տրիվիալ Դաս - այն դասն է որը՝

1. պարունակում է տրիվիալ լռելյան (default) կոնստրուկտոր

2. չի պարունակում ոչ տրիվիալ ընդորինակող կոնստրուկտոր

3. չի պարունակում ոչ տրիվիալ տեղափոխման կոնստրուկտոր

4. չի պարունակում ոչ տրիվիալ ընդորինակող վերագրման օպերատոր (copy assignment operator)

5. չի պարունակում ոչ տրիվիալ տեղափոխման վերագրման օպերատոր (move assignment operator)

6. պարունակում է տրիվիալ դեստրուկտոր

Ստանդարտ դասավորությամբ դասը-դա դասն է, որը՝

1. չի պարունակում ոչ ստատիկ անդամ-տվյալներ, որոնք ունեն ունեն ոչ ստանդարտ դասավորությամբ դասի տիպ(կամ այդպիսի տիպի զանգված) կամ հղման տիպ

2. չի պարունակում վիրտուալ ֆունկցիաներ

3. չի պարունակում վիրտուալ հիմքային(base) դաս

4. ունի միևնույն հասանելիության տեսակը (`public`, `private`, `protected`) բոլոր ոչ ստատիկ անդամ-տվյալների համար

5. չի պարունակում ոչ ստանդարտ դասավորությամբ հիմքային դաս

6. չի հանդիսանում դաս, որը միառժամանակ պարուանկում է ժառանգված և չժառանգված ոչ ստատիկ անդամ-տվյալներ, կամ միարժամանակ մի քանի հիմքային դասերից ժառանգված ոչ ստատիկ անդամ-տվյալներ

7. չի պարունակում հիմքային դասեր նույն տիպի ինչ առաջին ոչ ստատիկ անդամ-տվյալներ(եթե այդպիսիք կան)

### Կոմպիլյացիայի արագացում
#### Արտաքին կաղապարներ

Ստանդարտ **[[C++]]** ում կոմպիլիատորը պետք է инстанцировать կաղապարը ամեն անգամ, երբ հանդիպում է в единице трансляции его полную специализацию.

Դա կարող է զգալիորեն մեծացնել կոմպիլիացիայի ժամանակը, մանավանդ այն ժամանակ, երբ կաղապարը инстанцирован նույն պարամետրերով տրանսլիացիայի միավորների մեծ թվում։ Ներկայումս չկա ձև C++ ին հայտնելու, որ инстанцирования չպետք է լինի։

**C++11** ում ներմուծվել է արտաքին կաղապարների գաղափարը։**C++11** ում կա գրելաձև կոմպիլիատորին հասկացնելու, որ կաղապարը պետք է инстанцирован

որոշակի կետում։


```cpp
template class std::vector;
```

C++ ում չկա հնարավորություն արգելելու կոմպիլիատորին инстанцировать կաղապարը Տռանսլիացիայի միավորում։ **C++11** ը ուղղակի ընդլայնել է այս գրելաձևը(syntax)


```cpp
extern template class std::vector;
```

Այս արտահայտությունը ասում է կոմպիլիատորին не инстанцировать տվյալ Տռանսլիացիայի միավորում։

### Օգտագործման հարմարավետության բարձրացում
Այս հնարավորությունները նախատեսված են լեզվի օգտագործումը հեշտացնելու համար։

Դրանք հնարավորություն են տալիս ուժեղացնել տիպային անվտանգությունը, մինիմալացնել կոդի կրկնօրինակումը, դժվարեցնել կոդի սխալ օգտագործումը և այլն։

#### Սկզբնարժեքավորման ցուցակներ
Սկզբնարժեքավորման ցուցակների հասկացությունը **[[C++]]** եկել է **[[C]]** ից։ Գաղփարը կայանում է նրանում, որ կառուցվածքը կամ զանգվածը կարող են ստեղծված լինել արժեքների ցուցակի միջոցով, ընդորում կառուցվածքի անդամների հերթականությամբ։

Սկզբնարժեքավորման ցուցակները ռեկուրսիվ են, ինչը թույլ է տալիս օգտագործել դրանք

կառուցվածքի զանգվածի և կառուցվածքի մեջ ներդրված կառուցվածքի ժամանակ։


```cpp
struct Object
{
 float first;
 int second;
};

Object scalar = {0.43f, 10}; // մեկ օբյեկտ, որտեղ first=0.43f և second=10
Object anArray[] = ; // երեք տարր պարունակող զանգված
```


Սկզբնարժեքավորման ցուցակները շատ օգտակար են ստատիկ ցուցակների և այն դեպքերում, երբ պետք է կառուցվածքը սկզբնարժեքավորել կոնկրետ արժեքով։

**[[C++]]** ը նաև պարունակում է կոնստրուկտորներ, որոնք կարող են պարունակել օբեկտների սկզբնարժեքավորման ընդհանուր մասը։

**[[C++]]** ի ստանդարտը թույլ է տալիս օգտագործել սկզբնարժեքավորման ցուցակներ

կառուցվածքների և դասերի համար այն պայմանով, որ դրանք համապատասխանում են

պարզ տվյալների տիպի(POD) սահմանմանը։

Դասերը, որորնք չեն հանդիսանում POD, չեն կարող սկզբնավորման համար օգտագործել

սկզբնարժեքավորման ցուցակներ, դա վերբերվում է նաև ստանդարտ **[[C++]]**ի կոնտեյներներն, ինչպիսիք են վեկտորը։

C++11 ը կապել է սկզբնարժեքավորման ցուցակների գաղափարը և կաղապար դասը,

`std::initializer_list` անունով։ Դա թույլ է տվել կոնստրուկտորնեին և այլ ֆունկցիաներին ստանալ սկզբնարժեքավորման ցուցակները որպես պարամետրեր։ օրինակ ՝


```cpp
class SequenceClass
{
 public: SequenceClass(std::initializer_list list); 
};
```


Նկարագրման այս ձևը թույլ է տալիս ստեղծել `SequenceClass` ամբողջ թվերի հաջորդականությունից հետևյալ կերպ՝ `SequenceClass someVar= {1, 4, 5, 6}`;

Այս օրինակում ցույց է տված սկզբնարժեքավորման ցուցակների հատուկ տիպի կոնստրուկտորների աշխատանքը։ Դասերը, որոնք պարունակում են այսպիսի կոնստրուկտորներ, մշակվում են հատուկ ձևով սկզբնարժեքավորման ժամանակ։

`std::initializer_list<>` դասը սահմանված է **C++ 11** ի ստանդարտ գրադարանում(`STL`)։

Սակայն այս դասի օբկտները կարողեն ստեղծվել **C++11** ի կոմպիլիատորով միայն ստատիկ, օգտագործելով {} այս տիպի փակագծերը։ Ցուցակը ստեղծումից հետո կարող է կրկնօրինակվել, սակայն այն կլինի կրկնօրինակում հղումով(`copy by reference`)։

Սկզբնարժեքավորման ցուցակը հանդիսանում է հաստատուն՝ ոչ անդամները և ոչ էլ տվյալները ստեղծումից հետո փոփոխման ենթակա չեն։

Քանի որ `<std::initializer_list<>` ը հանդիսանում է լիարժեք տիպ, այն կարող է օգտագործվել ոչ միայն կոնստրուկտորներում։ Հասարակ ֆունկցիաները կարող են ստանալ սկզբնարժեքավորման ցուցակները որպես արգումենտ(պարամետր)։ Օրինակ՝


```cpp
void FunctionName(std::initializer_list list);
FunctionName({1.0f, -3.45f, -0.4f});
```


Ստանդարտ կոնտեյներները կարող են սկզբնարժեքավորվել հետևյալ կերպ.


```cpp
std::vector v = { "xyzzy", "plugh", "abracadabra" };
std::vector v{ "xyzzy", "plugh", "abracadabra" };
```


#### Ունիվերսալ սկզբնարժեքավորում
**[[C++]]** ի ստանդաարտ կան մի շարք խնդիրներ կապված սկզբնարժեքավորման տեսակների հետ։ Գոյություն ունեն տիպերի սկզբնարժեքավորման մի քանի եղանակներ, և ոչ բոլորն են հանգեցնում նույն արդյունքին։ Օրինակ՝ ավանդական սկզբնարժեքավորման կոնստրուկտորի գրելաձևը կարող է հասկացվել կոմպիլիատորի կողմից որպես ֆունցիայի նկարագրում, ուստի պետք է ձեռնարկել լրացուցիչ միջոցներ, որպեսզի կոմպիլիատորը չսխալվի վերլուծության ժամանակ։ Միայն խմբավորման և (`POD`) տիպերը կարող են սկզբնաորվել արգումենտների սկզբնավորուման միջոցով (`SomeType var = {/*stuff*/};`)

**C++11** ը ներկայացնում է գրելաձև, որը թույլատրում է բոլոր տեսակի օբեկտների միացիալ սկազբնարժեքավորում, սկզբնարժեքավորման ցուցակների գրելաձևի ընդլայման օգնությամբ։


```cpp
struct BasicStruct
{
 int x;
 double y;
};

 struct AltStruct 
{
 AltStruct(int x, double y) 
          : x_(x)
            , y_(y) 
{}
 private:
 int x_;
 double y_;
 };
 BasicStruct var1{5, 3.2}; 
AltStruct var2{2, 4.3};
```


`var1` ի սկզբնավորումը աշխատում է այնպես, ինչպես արգումենտներով սկզբնարժեքավորման ժամանակ, այսինքն, յուրաքանչյուր օբյեկտ սկզբնարժեքավորված կլինի սկզբնարժեքավորման ցուցակի իրեն համապատասխանող արժեքի կրկնօրինակով։ Անհրաժեշտության դեպքում կկիրառվի տիպերի անուղղակի փոխարկում(կոնվերտացիա)։Եթե անհրաժեշտ փոխարկումը հնարավոր չէ, կոդը

կհամարվի սխալ։

`var2` ի սկզբնարժեքավորման ժամանակ կկանչվի կոնստրուկտոր։

Տրված է հնարավորություն գրելու նմանատիպ կոդ.


```cpp
struct IdString
{
 std::string name;
 int identifier; 
};

 IdString GetString()
 {
 return {"SomeName", 4}; //   ուշադրություն դարձրեք տիպի ակնհայտ հայտարարման բացակայությանը
 };
```


Ունիվերսալ սկզբնարժեքավորումը ամբողջովին չի փոխարինում կոնստրուկտորով

սկզբնարժեքավորելու գրելաձևին։ Եթե դասում կա կոնստրուկտոր, որը որպես արգումենտ ստանում է սկզբնարժեքավորման ցուցակ(ИмяТипа(initializer_list);), այն կունենա ավելի բարձր առաջնայնություն համեմատած մյուս օբեկտ ստեղծելու միջոցների։ Օրինակ, **C++**-ում `std::vector` պարունակում է, որպես արգումենտ սկզբնարժեքավորման ցուցակ ստացող կոնստրուկտոր


```cpp
std::vector theVec{4};
```


Այս կոդը կբերի որպես արգումենտ սկզբնարժեքավորման ցուցակ ստացող կոնստրուկտորի կանչի, այլ ոչ թե մի պարամետրով կոնստրուկտորի, որը ստեղծում է կոնտեների տրված չափով։ Այդ կոնստրուկտորի կանչի համար օգտագործողը պետք է օգտագործի կոնստրուկտորի կանչի ստանդարտ գրելաձև։

#### Տիպերի դուրսբերումը
Ստանդարտ C++ փոփոխականը պետք է բացահայտ հայտարարված լինի։ Սակայն կաղապար տիպերի և դրանցով մետածրագրավորման (metaprogramming) ի հայտ գալով, որոշ արտահայտությունների տիպերը, ֆունկցիաների վերադարձվող արժեքները հնարավոր չէ հեշտությամբ նշել։ Դա հանգեցնում է դժվարությունների, փոփոխականների միջանկյալ տվյալները պահելուց։ Երբեմն կարող է անհրաժեշտ լինել իմանալ մետածրագրավորման գրադարանի ներքին միջոցները։

C++11-ը առաջարկում է երկու տարբերակ թեթևացնելու այս խնդիրը։ Առաջին՝ ակնհայտ սկզբնարժեքավորվող փոփոխականը կարող է պարունակել `auto` բանալի բառը։ Դա կբերի նրան, որ փոփոխականը կստեղծվի սկզբնարժեքավորվող արժեքի տիպի։


```cpp
auto someStrangeCallableType = std::bind(&SomeFunction, _2, _1, someObject);
auto otherVariable = 5;
```

`someStrangeCallableType-ը ` կլինի այն տիպի, ինչ տիպ կվերադարձնի`std::bind `ֆունկցիան տրված արգումենտների համար։ Այդ տիպը հեշտությամբ դուրս կբերվի կոմպիլիատորի կողմից սեմանտիկ վերլուծության ընթացքում, ինչը ծրագրավորողին կտրվեր մի շարք բարդ հետազոտություններից հետո։
` otherVariable ` տիպը նույնպես հեշտությամբ սահմանվել, սակայն այն նույն հեշտությամբ կարող էր սահմանվել ծրագրավորողի կողմից։ Դա int տիպն է, այնպիսին ինչչպիսին ամբողջ հաստատունինը։
Բացի դրանից, կոմպիլիացիայի ժամանակ արտահայտությունների տիպերի որոշման համար օգտագործվում է decltype բանալի բառը։ Օրինակ՝

```cpp
int someInt;
decltype(someInt) otherIntegerVariable = 5;
```

decltype ը շատ ավելի արյունավետ է օգտագործել `auto` ի հետ, որովհետև `auto` հայտարարված տիպը հայտնի է միայն կոմպիլիատորին։ Բացի դրանից, decltype ի օգտագործումը կարող է շատ օգտակար լինել արտահայտություններում, որտեղ օգտագործվում են օպերատորների գերբեռնում և կաղապարների սպեցիալիզացիա։
`auto` -ն կարող է օգտագործվել նաև կոդի կոկիկության համար, օրնակ.

```cpp
for (vector::const_iterator itr = myvec.cbegin(); itr != myvec.cend(); ++itr)
```

փոխարեն կարելի է գրել

```cpp
for (auto itr = myvec.cbegin(); itr != myvec.cend(); ++itr)
```

Տարբերույունը ակնհայտ է դառնում, երբ ծրագրավորողը օգտագործում է մեծ թվով կոնտոյներներ, չնայած այն բանին, որ այժմ կա ավելորդ կոդի փոքրացման միջոց՝typedefի օգտագործում։
decltype նշված տիպը կարող է տարբերվել `auto` ով դուրս բերված տիպից

```cpp
#include <vector>
int main()
{
    const std::vector v(1);
    auto a = v[0]; // a֊-ի տիպն int է
    decltype(v[0]) b = 1; // b-֊ի տիպը const int& է (std::vector::operator[](size_type) const մեթոդի արժեքի տիպը) 
    auto c = 0; // c֊-ի տիպն int է
    auto d = c; // d֊-ի տիպն int է
    decltype(c) e; // e-֊ի տիպն int է՝ c֊-ի տիպը
    decltype((c)) f = c; // f-ի տիպը int& է, քանի որ (c)-֊ն lvalue է
    decltype(0) g; // g֊-ի տիպը int է, քանի որ 0֊-ն rvalue է
}
```


#### For - հավաքածուի ցիկլ
Ստանդարտ **[[C++]]**-ում տարրերի հավաքածուն վերցնելու համար անհրաժեշտ է բավականին ծավալուն կոդ։ Շատ լեզուներում, օրինակ **[[C#]]**-ում, գոյություն ունի միջոց «foreach», որը ավտոմատ կերպով վերցնում է հավաքածուի տարրերը սկզբից մինչև վերջ։ **[[C++]]**-ը տրամադրում է այդպիսի միջոց։ `for`-ի սահմանումը թույլատրում է ավելի հեշտ վերցնել հավաքածուի տարրերը.


```cpp
int my_array[5] = {1, 2, 3, 4, 5};
for(int &x : my_array)
{
 x *= 2;
}
```


Այս տիպի `for` ցիկլը անգլերեն կոչվում է «range-based for», այն կայցելի հավաքածուի յուրաքանչյուր էլեմենտ։ Այն կիրառելի կլինի **[[C]]** լեզվի զանգվածների, ինիցիալիզատորների ցուցակների և այն բոլոր տիպերի համար, որոնց համար սահմանված են `begin()` և `end()` ֆունկցիաները, որոնք վերադարձնում են իտերատորներ։ Ստանդարտ գրադարանի բոլոր կոնտեյներները, որոնք ունեն `begin/end` զույգը կաշխատեն `for` ցիկլի հետ հավաքածույով։ Այդպիսի ցիկլը կաշխատի **[[C]]** լեզվի զանգվածների հետ նույնպես, քանի որ **C++11** ստանդարտը արհեստականորեն դրանց համար սահմանում է անհրաժեշտ տիպերը (`begin`, `end` և այլն )։

#### Լյամբդա-ֆունկցիաներ և արտահայտություններ
Ստանդարտ C++ լեզվում գրադարանային ալգորիթմներից օգտվելիս հաճախ կարիք է առաջանում սահմանել ֆունկցիա-պրեդիկատ հենց այնտեղ, որտեղ որ կանչվում է ալգորիթմը։ Լեզվում գոյություն ունեցող միակ մեխանիզմը ֆունկտոր դաս հայտարարելն էր (ֆունկցիայի ներսում սահմանված դասի օբյեկտ փոխանցելը ալգորիթմը արգելում է (*Meyers, Effective STL)*)։ Իրականում այս տարբերակը համարվում է ժամանակատար և բարդացնում է կոդի ընթերցանելիությունը։ Բացի այդ, C++-ի կանոններն արգելում են դրանց օգտագործումը կաղապարներում՝ դրանով իսկ անհնար դարձնում դրանց նպատակային օգտագործումը։ Ակնհայտ լուծում է հանդիսանում C++11 ստանդարտի լյամբդա-ֆունկցիաների և արտահայտությունների կիրառումը։ Լյամբդա-ֆունկցիաները հայտարարվում են հետևյալ կերպ՝


```cpp
[](int x, int y) { return x + y; }
```


Այս անանուն ֆունկցիայի համար վերադարձվող արժեքի տիպը որոշվում է որպես `decltype(x+y)`։ Վերադարձվող տիպը կարելի է բաց թողնել այն ներկայացված է որպես `return expression`: Դա սահմանափակում է լյամբդա-արտահայտությանը մինչև մեկ արտահայտություն։
Վերադարձվող տիպը կարելի է նաև բացահայտ նշել։


```cpp
[](int x, int y) -> int { int z = x + y; return z; }
```


Այս դեպքում ստեղծվում է ժամանակվոր `z` փոփոխական վերադարձվելիք արժեքը հիշելու համար։ Ինչպես և սովորական ֆունկցիաներում, այդ ժամանակավոր փոփոխական չի պահվում կանչերից հետո։
Վերադարձվող տիպը լրիվ բաց է թողնվում, եթե ֆունկցիան արժեք չի վերադարձնում(այսինքն `void`)։ Հնարավոր է օգտագործել նաև հղումներ փոփոխականների վրա, եթե դրանք հայտարարված են նույն տեսանելիության տիրույթում ինչ լյամբդա-ֆունկցիան։

```cpp
std::vector<int> someList;
int total = 0;
std::for_each(someList.begin(), someList.end(), [&total](int x) {
  total += x;
});
std::cout << total
```

Սա ցույց կտա ցուցակի բոլոր էլեմենտների գումարը։ Քանի որ `total` փոփոխականը հղվում է ստեկի մեջ գտնվող այլ փոփոխականի վրա այդ իսկ պատճառով այն կարող է փոփոխել դրա արժեքը։
Փոփոխականները կարող են փոխանցվել ֆունկցիային առանց `&` նշանի, սակայն այդ դեպքում դրանց արժեք ֆունկցիան կկրկնորինակի։
Լյամբդա ֆունկցիաները կարող են օգտագործել իրենց տեսանելիության տիրույթում գտնվող փոփոխականները առանց ականհայտ հղումների։

```cpp
std::vector<int> someList;
int total = 0;
std::for_each(someList.begin(), someList.end(), [&](int x) {
  total += x;
});
```

Ներքին ռեալիզացիաները կարող են տարբերվել, բայց ենթադրվում է, որ լյամբդա ֆունկցիան կպահպանի ցուցիչը ֆունկցիյա ստեկի վրա, այլ ոչ թե կաշխատի ստեկի առանձին փոփխականների հղումների հետ։
Եթե `[&]` փոխարեն օգտագործվի `[=]`, ապա բոլոր փոփոխականները կկրկնորինակվեն և լյամբդա ֆունկցիան հնարավոր կլինի օգտագործել անկախ ընթացիկ փոփոխականների հայտարարման տիրույթից։
Լռելիությամբ տվյալները փոխանցելը կարելի է լրացնել առանձին փոփոխականների ցուցակներով։ Եթե անհրաժեշտ է բոլոր արգումենտները փոխանցել հղումով իսկ մեկը ոչ՝ կարելի է վարվել հետևյալ կերպ.

```cpp
int total = 0;
int value = 5;
[&, value](int x) { total += (x * value); } (1);
```

Այս դեպքում `total`կփոխանցվի հղումով իսկ `value` արժեքով։
Եթե լյամբդա ֆունկցիան սահմանված է դասի մեթոդի մեջ ապա այն այդ դասի համար ընկեր (անգլ. friend) ֆունկցիա է։ Այդպիսի ֆունկցիաները կարող են դիմել դասի ներքին անդամներին և օգտագործել դասի տիպի հղումներ։

```=
[](SomeType *typePtr) { typePtr->SomePrivateMemberFunction(); }
```

Սա կաշխատի միայն այն դեպքում լյամդա ֆունկցիան ստեղծվել է `SomeType` դասի մեթոդում։
Հատուկ ձևով սահմանված է `this` ցուցիչի հետ աշխատանքը։ Այն պետք է բացահայտ նշվի լյամբդա ֆունկցիայում։

```cpp
[this]() { this->SomePrivateMemberFunction(); }
```

`[&]` կամ `[=]` օգտագործումը ինքնստինքյան `this` ցուցիչը դարձնում է հասանելի։
Լյամբդա ֆունկցիայի տիպը կախված է դրա ռեալիզացիայից, այդ տիպի անունը հայտնի է միայն կոմպիլիատորին։ Եթե անհրաժեշտություն կա լյամբդա ֆունկցիան փոխանցել որպես արգումնետ, ապա այն պետք է լինի կաղապար տիպի կամ պահպանված լինի օգտագործելով `std::function`-ը։ Օգտագործելով `auto` բանալի բառը (անգլ. keyword) կարող ենք հիշել լյամբդա ֆունկցիան։

```cpp
auto myLambdaFunc = [this]() { this->SomePrivateMemberFunction(); };
```


#### Ֆունկցիաների գրելաձևի այլընտրանքային մոտեցում
Երբեմն անհրաժեշտություն է առաջանում իրականացնել կաղապար ֆունկցիա, որի վերադարձվող արժեքը պետք է լինի որևէ արտահայտության տիպի։


```cpp
template <typename LHS, typename RHS>
    RETURN_TYPE AddingFunc(const LHS &lhs, const RHS &rhs) // ինչպիսի՞ն պետք է լինի վերադարձվող տիպը
{
    return lhs + rhs;
}
```


Որպեսզի `AddingFunc(x, y)` արտահայտությունը ունենա նույն տիպը ինչ `lhs + rhs`, `x` և `y` արգումնենտերը փոխանցելու դեպքում, C++11 լեզվում կարելի է օգտագործել հետևյալ հայտարարությունը.


```cpp
template <typename LHS, typename RHS>
    decltype(std::declval<const LHS &>() + std::declval<const RHS &>())
        AddingFunc(const LHS &lhs, const RHS &rhs)
{
    return lhs + rhs;
}
```


Իհարկե ավելի լավ կլիներ `std::declval<const LHS &>()` և `std::declval<const RHS &>()` փոխարեն օգտագործել համապատասխանաբար `lhs` և `rhs`։ Սակայն հաջորդ տարբերակում,


```cpp
template <typename LHS, typename RHS>
    decltype(lhs + rhs) AddingFunc(const LHS &lhs, const RHS &rhs) // Թույլատրելի չէ C++11-ում
{		
    return lhs + rhs;
}
```


որը ավելի պարզ է թվում, `lhs` և `rhs` իդենտիֆիկատորները օգտագործվում են `decltype` օպերանդում և չեն կարող օգտագործվել, որպես պարամետրներ որոնք ավելի ուշ են հայտարարվելու։ Այս խնդրի լուծման համար **C++11** ստանդարտում նախատեսված է ֆունկցիաների գրելաձևի նոր տարբերակ, որում կարելի է ֆունկցիայի վերադարձվող տիպը նշել վերջում։


```cpp
template <typename LHS, typename RHS>
    auto AddingFunc(const LHS &lhs, const RHS &rhs) -> decltype(lhs + rhs)
{	
    return lhs + rhs;
}
```


Պետք է նշել, որ վերոհիշյալ գրելաձևը որոշ դեպքերում բավականին երկար է ստացվում։


```cpp
template <typename LHS, typename RHS>
    auto AddingFunc(LHS &&lhs, RHS &&rhs) ->
        decltype(std::forward<LHS>(lhs) + std::forward<RHS>(rhs))
{
    return std::forward<LHS>(lhs) + std::forward<RHS>(rhs);
}
template <typename LHS, typename RHS>
    auto AddingFunc(LHS &&lhs, RHS &&rhs) ->
        decltype(std::declval<LHS>() + std::declval<RHS>()) // նույն արդյունքն է ինչ նախորդ դեպքում
{
    return std::forward<LHS>(lhs) + std::forward<RHS>(rhs);
}
template <typename LHS, typename RHS>
    decltype(std::declval<LHS>() + std::declval<RHS>()) // նույն արդյունքն է,ինչ տիպը վերջ տեղափոխելու դեպքում
        AddingFunc(LHS &&lhs, RHS &&rhs)
        
{
    return std::forward<LHS>(lhs) + std::forward<RHS>(rhs);
}
```


Նոր գրելաձևը կարելի է օգտագործել ավելի պարզ հայտարարություններում ու նկարագրություններում։

```cpp
struct SomeStruct
{
    auto FuncName(int x, int y) -> int;
};

auto SomeStruct::FuncName(int x, int y) -> int
{
    return x + y;
}
```


`auto` բանալի բառի (Անգլերեն. keyword) օգտագործումը նշանակում է որ վերադարձվող տիպը ավելի ուշ է նշվելու, այլ ոչ թե ավտոմատ կերպով դուրս է բերվելու։

#### Օբյեկտների կոնստրուկտորների բարելավում
Ստանդարտ **[[C++]]** թույլ չի տալիս դասի մի կոնստրուկտորի միջից այդ նույն դասի այլ կոնստրուկտոր կանչել, կոնստրուկտորները պետք է իրենց մեջ ինիցիալիզացնեն դասի բոլոր տվյալները, կամ դա անեն դասի այլ մեթոդի օգնությամբ։ Ոչ կոնստանտ տվյալները չեն կարող ինցիալիզացվել հենց հայտարարման պահին։
**C++11** օգնում է ազատվել այս խնդիրներից։
Նոր ստանդարտը թույլ է տալիս դասի մի կոնստրուկտորից նույն դասի այլ կոնստրուկտոր կանչել։ Սա թույլ է տալիս գրել կոնստրուկտորներ, որոնք կրկնում են այլ կունստրուկտորների վարքը, առանց ավելորդ անգամ կոդը կրկնելու։
`Օրինակ.`

```cpp
class SomeType {
    int number;

public:
    SomeType(int new_number) : number(new_number) {}
    SomeType() : SomeType(42) {}
};
```

Օրինակից պարզ է, որ `SomeType` առանց արգումենտների կոնստրուկտորը կանչում է նույն դասի մեկ այլ կոնստրուկտոր, որի միջոցով ինիցիալիզացնում է `number` փոփոխականը։ Նույն արդյունքին կարելի է հասնել, եթե 42 արժեքը փոփոխականին տրվեր հենց սահմանման ժամանակ։

```cpp
class SomeType {
    int number = 42;

public:
    SomeType() {}
    explicit SomeType(int new_number) : number(new_number) {}
};
```

Դասի ցանկացած կոնստրուկտոր number փոփոխականին կվերագրի 42 արժեքը, եթե հենց ինքը ուրիշ արժեք չվերագրի։
Հատկանշական է, որ **[[C++03]]** համարում էր օբյեկտը կառուցված, եթե կոնստրուկտորը ավարտել է աշխատանքը, ապա **C++11** գոնե մեկ դելեգատ կոնստրուկտորի աշխատանքի ավարտից հետո մնացած կոնստրուկտորները կաշխատեն արդեն ամբողջովին կառուցված օբյեկտի վրա։ Անկախ դրանից ժառանգ դասի կոնստրուկտորները կաշխատեն միայն ծնող դասի բոլոր կոնստրուկտորների ավարտից հետո։

#### Վիրտուալ ֆունկցիաների բացահայտ վերասահմանում
Հնարավոր է, որ վիրտուալ մեթոդը փոփոխվի ծնող դասում, կամ ի սկզբանե սխալ գրված լինի ժառանգ դասի մեջ։ Նման դեպքերում այդ ֆունկցիան ժառանգ դասի մեջ չի փոխարինի ծնող դասի համապատասխան ֆունկցիային։ Հակառակ դեպքում, եթե ծրագրավորողը ճիշտ չնշի ֆունկցիաները ժառանգ դասերում, ապա մեթոդը սխալ կիրականացվի ծրագրի կատարման ընթացքում։
**Օրինակ.**

```cpp
struct Base {
    virtual void some_func();
};

struct Derived : Base {
    void sone_func();
};
```

Այստեղ ժառանգ դասում սահմանված ֆունկցիայի մեջ թույլ է տրված սխալ, որի հետևանքով այդ ֆունկցիան չի վերասահմանում ծնող դասի `Base::some_func`, և համապատասխանաբար չի կանչվի պոլիմորֆիկ կերպով ցուցչի կամ հղման միջոցով որը ցուցում/հղվում է բազային օբյեկտի վրա։
**C++11** ստանդարտում նոր հնարավորություն կա նման թերությունները հայտնաբերել կոմպիլյացիայի ընթանցքում։ Հակառակ համատեղելիության պատճառով այս հնարավորությունը համարվում է ընտրովի։
**Օրինակ.**

```cpp
struct B
{
    virtual void some_func();
    virtual void f(int);
    virtual void g() const;
};

struct D1 : public B
{
    void sone_func() override;          // սխալ է` ֆունկցիայի սխալ անուն
    void f(int) override;               // ճիշտ է` վերասահմանում է համապատասխան ֆունկցիան
    virtual void f(long) override;      // սխալ է` պարամետրերի անհամապատասխան տիպեր
    virtual void f(int) const override; // սխալ է`ֆունկցիայի անհամապատասխան  cv-կվալիֆիկացիա    
    virtual int f(int) override;        // սխալ է` անհամապատասխան վերադարձվող տիպ
    virtual void g() const final;       // ճիշտ է` վերասահմանում է համապատասխան ֆունկցիան
    virtual void g(long);               // ճիշտ է` նոր վիրտուալ ֆունկցիա
};

struct D2 : D1
{
    virtual void g() const;             // սխալ է` փորձում է վերասահմանել վերջնական վերսահմանված ֆունկցիան
};
```

Ֆունկցիայի մոտ `final` բանալի բառի առկայությունը նշանակում է, որ այն հետագայում չի կարելի վերասահմանել։ Բացի այդ `final` բանալի բառի միջոցով սամանված դասից չի կարելի ժառանգել։

```cpp
struct F final
{
    int x, y;
};

struct D : F // սխալ է` final դասերից ժառանգումը արգելված է
{
    int z;
};
```


#### Զրոյական ցուցիչի հաստատուն
Դեռևս 1972 թ. C լեզվում `0` կոնստանտը երկու դեր ուներ՝ ամբողջ թիվ և զրոյական ցուցիչ։ Այդ անորոշության լուծումներից մեկը `NULL` մակրոսն է, որը սովորաբար ((`void*`)0) կամ `0` է։ C++ այս մասով տարբերվում է C-ից նրանով, որ միայն `0`-ն կարող է հանդես գալ որպես զրոյական ցուցիչ։ Դա ֆունկցիաների գերբեռնման ժամանակ բերում է խնդիրների։


```cpp
void foo(char *);
void foo(int);
```


Եթե `NULL` սահմանված է `0`, ապա `foo(NULL)` կանչի դեպքում կաշխատի `foo(int)` ֆունկցիան, այլ ոչ թե `foo(char *)`, ինչպես կարելի էր ենթադրել կոդի հպանցիկ դիտումից հետո, որտեղ, ամենայն հավանականությամբ ծրագրավորողը նկատի էր ունեցել հենց `foo(char *)` ֆունկցիայի կանչը։

C++11 ստանդարտի նորարություններից մեկն այն է, որ զրոյական ցուցիչները նկարագրելու համար ավելացել է `nullptr` բանալի բառը։ Այս կոնստանտը `std::nullptr_t` տիպի է, որը կարելի է բերել ցանկացած ցուցչային տիպի և համեմատել ցանկացած ցուցչի հետ։ Սակայն այս դեպքում ամբողջ տիպի բերում չի կատարվում։ Բացառություն է կազմում միայն `bool` տիպը։

Հակադարձ համատեղելիության ապահովման համար `0` կոնստանտը նույնպես կարելի է օգտագործել, որպես զրոյական ցուցիչ։

```cpp
char *pc = nullptr; // ճիշտ է
int *pi = nullptr; // ճիշտ է
bool b = nullptr; // ճիշտ է. b = false.
int i = nullptr; // սխալ է

foo(nullptr); // կանչվում է foo(char *), այլ ոչ թե foo(int);
```


#### Խիստ տիպայնացված թվարկումներ
Ստանդարտ C++-ում թվարկումները(Անգլերեն. enumeration) տիպերի բերման տեսանկյունից ապահով չեն։ Իրականում նրանք ներկայացված են ամբողջ թվերի տեսքով, անկախ նրանից, որ տարբեր թվարկումները իրականում տարբեր տիպեր են։ Դա իր հերթին թույլ է տալիս երկու տարբեր թվարկումների միջև համեմատություններ անել։ Միակ հնարավորությունը, որ տրամադրում է C++03-ը, թվարկումների ապահովության համար՝ չի թույլատրվում ամբողջ տիպերից կամ թվարկումներից անուղղակի տիպերի բերումը այլ թվարկումների։ Բացի այդ հիշողության մեջ (ամբողջ տիպերի տեսքով) ներկայացումը կախված է իրականացումից և ապահով չէ։ Վերջապես թվարկումները ունեն ընդհանուր տեսանելիության տիրույթ, որ թույլ չի տալիս տարբեր թվարկումների մեջ լինեն նույն անունով անդամներ։

C++11 տրամադրում է հատուկ տեսակի դասակարգումներ նման տիպի թվարկումների համար, ինչը ազատում է վերոհիշյալ թերություններից։ Նման դեպքերում օգտագործում են `enum class` հայտարարությունը (ինչպես նաև կարելի է օգտագործել `enum struct` հայտարարությունը)։


```cpp
enum class Enumeration {
    Val1,
    Val2,
    Val3 = 100,
    Val4, /* = 101 */
};
```


Այսպիսի թվարկումը տիպերի բերման տեսանկյունից համարվում է ապահով։ Դասային տիպի թվարկումները հնարավոր չէ ոչ բացահայտ կերպով բերել ամբողջ թվերի։ Որպես հետևանք արգելված է թվարկումնեի համեմատումը ամբողջ թվերի հետ։
Այժմ թվարկումները տիպը կախված չեն իրականացումից։ Լռելիությամբ ինչպես վերոհիշյալ դեպքն է՝ տիպը `int` է, բայց մնացած դեպքերում այդ տիպը կարելի նշել ինքնուրույն հետևյալ կերպ.

```cpp
enum class Enum2 : unsigned int {Val1, Val2};
```

Թվարկումների անդամների հասանելիության տիրույթը համընկնում է հենց թվարկման հասանոլիության տիրույթի հետ։ Տարբեր էլեմենտներ օգտագործելու համար պետք է նշել նաև նրա տիպը՝`Enum2::Val1`, իսկ ուղղակի `Val1`-ի տիպը որոշված չէ։

Սովորական թվարկումների դեպքում **C++11** թույլ է տալիս նշել տեսանելության տիրույթը և տիպը։

```cpp
enum Enum3 : unsigned long {Val1 = 1, Val2};
```

Տվյալ օրինակում թվարկման էլեմենտները սահմանված են `Enum3` տեսանելիության տիրույթում (`Enum3::Val1`), բայց համատեղելիության ապահովման նպատակով դրանք հասանելի են նաև ընդհանուր տեսանելիության տիրույթում։
Ինչպես նաև **C++11** ստանդարտում թվարկումները կարելի է նախօրոք հայտարարել, ինչը նախորդ և ոչ մի ստանդարտում չէր թույլատրվում, քանի որ թվարկման չափը ուղղակիորեն կախված է իր անդամներից։ Նման հայտարարություններից կարելի է օգտվել միայն թվարկման չափը նշելու դեպքում։

```cpp
enum Enum1; // սխալ է, տիպը որոշված չէ։
enum Enum2 : unsigned int; // ճիշտ է C++11-ում, տիպը նշված է։
enum class Enum3; // ճիշտ է C++11-ում, լռելիությամբ տիպը — int:
enum class Enum4 : unsigned int; // ճիշտ է C++11-ում։
enum Enum2 : unsigned short; // սխալ է C++11-ում, քանի որ այս տիպը արդեն հայտարարված է։
```


#### Անկյունավոր փակագծեր
C++-ի ստանդարտ շարահյուսական վերլուծիչները (անգլ. parser) «`>>`» կոմբինացիան ընդունում են որպես աջ տեղաշարժի օպերատոր։ Ներդրված կաղապար արգումենտների դեպքում բացատանիշի բացակայությունը այդ փակագծերի միջև համարվում է սխալ։
C++11-ը լավացնում է վերլուծիչի վարքը այդպիսի դեպքերում, այսինքն մի քանի աջ եզրային փակագծերը կընկալվեն որպես կաղապար արգումենտների ցուցակի ավարտ։

Նկարագրված վարքը կարելի է ձևափոխել ի օգուտ նախկինի՝ կլոր փակագծերի միջոցով։

```cpp
template<class T> class Y { /* ... */ };
Y<X<1>> x3; // ճիշտ է, նույնն է, ինչ "Y<X<1> > x3;".
Y<X<6>>1>> x4; // սխալ է, պետք է լինի "Y<X<(6>>1)>> x4;".
```

Ինչպես երևում է վերը նշված օրինակում այս փոփոխությունը այնքան էլ համատեղելի չէ նախկին ստանդարտի հետ։

#### Բացահայտ տիպերի բերման օպերատորներ
**[[C++]]** Ստանդարտ-ում գոյություն ունի `explicit` բանալի բառը, որը կարելի է օգտագործել մեկ պարամետրներով կոնստրուկնորների հետ, որպեսզի դրանք չոգտագործվեն ոչ բացահայտ տիպերի բերման ընթացքում։ Սակայն դա չի ազդում իրական տիպերի բերման օպերատորների վրա։ Դասերը կարող են ունենալ `operator bool()` օպերատորը, և այդ դեպքում ճիշտ կլինի `if`(`variable`) արտահայտությունը։ Խնդիրն այն է, որ այդ օպերատորը չի պաշտպանում այլ չկանխատեսված ձևափոխումներից։ Քանի որ **[[C++]]**-ում `bool` համարվում է մաթեմատիկական տիպ, այդ իսկ պատճառով այն կարելի բերել ցանկացած թվի տիպի։
**C++11** ստանդարտում `explicit` բանալի բառը կիրառելի է նաև ձևափոխման օպերատորների հետ։ Ինչպես կոնստրուկտորների դեպքում այնպես էլ այստեղ այն պաշտպանում է չնախատեսված ձևափոխումներից։ Սակայն այն դեպքերում, երբ ծրագիրը ակնկալում է `bool` տիպ, ձևափոխությունը տեղի է ունենում։

#### Կաղապարներում typedef
**[[C++]]** ստանդարտում հնարավոր է `typedef` բառի միջոցով ստեղծել հոմանիշներ այլ տիպերի համար, այդ թվում օգտագործվում է կաղապարների համար՝ հոմանիշների միջոցով վերցնելով նրա բոլոր պարամետրերը։ Բայց հնարավոր չէ ստեղծել կաղապարի հոմանիշ։
Օրինակ.

```cpp
template<typename First, typename Second, int third>
class SomeType;
```



```cpp
template<typename Second>
typedef SomeType<OtherType, Second, 5> Typedef Name; // հնարավոր չէ C++-ով
```


Սրա կոմպիլյացիան չի անցնի։

**C++11**-ում ավելացվել է այս հնարավորությունը հետևյալ կերպ.


```cpp
template<typename First, typename Second, int third>
class SomeType;

template<typename Second>
using Typedef Name = SomeType<OtherType, Second, 5>;
```


C++ 11-ում `using` հրահանգով հնարավոր է ստեղծել կեղծանուն տվյալների տիպերի համար։


```cpp
Typedef void (*OtherType)(double);	// հին ձևը
using OtherType =void (*)(double);	// նոր ձևը
```


#### Հեռացնել սահմանափակումները union-ի միջոցով
Նախորդ **[[C++]]** ստանդարտներում գոյություն ուներ մի շարք սահմանափակումներ, միավորումներում (անգլ. union) դասերի տիպեր օգտագործելիս։ Հաճախ միավորվող օբյեկտները չեն կարող պահել ոչ դատարկ կոնստրուկտորները։ **C++ 11**-ը բացառում է այդպիսի սահմնափակումների մի մասը։ Ահա մի պարզ օրինակ, որը թույլ է տալիս **C++ 11։**

```cpp
// placement new
#include <new>

struct Point {
    Point() {}
    Point(int x, int y): x_(x), y_(y) {}
int x_, y_;
};
union U {
int z;
double w;

 Point p;  // սխալ է '''[[C++03]]''' համար, քանի որ կա ոչ դատարկ կոնստրուկտոր։ Սակայն այն ճիշտ աշխատում է C++11-ում.
U() { new( &p ) Point(); } //Միավորման ընթացքում չեն սահմանվում ոչ պարզ մեթոդները։
// Անհրաժեշտության դեպքում դրանք կարելի է հեռացնել, որպեսզի աշխատի մեխանիկական միավորումը
};
```

Փոփոխությունները չեն ազդում առկա կոդի վրա, քանի որ այն միայն փոքրացնում են տվյալ սահմանափակումները։

#### Հատուկ իմաստ կրող անուններ
`override` և `final` իդենտիֆիկատորները հատուկ իմաստ ունեն այն դեպքերում, միայն որոշակի դեպքերում։ Մնացած դեպքերում դրանք օգտագործվում են ինչպես սովորական իդենտիֆիկատորներ (ինչպես օրինակ փոփոխականի կամ ֆունկցիյաի անունը)։

### Ընդլայնված ֆունկցիոնալություն
Այս բաժնում սահմանվում են նոր հնարավորություններ, որը առաջ հնարավոր չէր օգտագործել կամ էլ պետք էր հատուկ հնարավորություններով գրադարաններ։

#### Անորոշ քանակի պարամետրերով կաղապարներ
Մինչև C++ 11֊-ը կաղապարները (նաև ֆուկցիաները և դասերը) կարող էին ունենալ միայն որոշակի ֆիքսված թվով պարամետրեր, որոնք հայտարարվում էին կաղապարի նկարագրության մեջ։ C++ 11֊ը թույլ է տալիս ստեղծել տարբեր տիպեր և անորոշ քանակով պարամետրեր ունեցող կաղապարներ։ Օրինակ․


```cpp
template<typename... Values>
class tuple;
```


`tuple` (շարք, n-յակ) կաղապար ֊դասը որպես կաղապարի անդամներ ընդունում է ցանկացած թվով տիպերի անուներ։


```cpp
class tuple<int, std::vector<int>, std::map<std::string, std::vector<int>>> some_instance_name;
```


փոփոխականները կարող են նաև բացակայել․ `class tuple<> some_instance_name` նույնպես կաշխատի։
 
Որպեսզի կաղպարն առանց փոփոխականի տեղի չունենա, ապա պետք է գրել հետևյալ կերպ.


```cpp
template<typename First, typename... Rest>class tuple;
```


Փոփոխվող արգումենտների քանակով կաղապարները կիրառելի են նաև ֆունկցիաների դեպքում, ինչը թույլ է տալիս օգտագործել դրանք անորոշ քանակի արգումենտներ ունեցող ֆունկցիաներում(օրինակ՝ printf), և ոչ պարզ օբյեկտներ կառուցելու ընթացքում։


```cpp
template<typename... Params>void printf(const std::string &str_format, Params... parameters);
```

`...` այս օպերատորը այստեղ ունի երկու իմաստ։ `Params`-ից ձախ գտնվելու դեպքում օպերատորը նշանակում է, որ պարամետրերը վերջավոր են։ Օգտագործելով վերջավոր պարամետրերի գաղափարը կաղապարում հնարավոր է հայտարարել 0 և ավելի փոփոխականներ։ Վերջավոր պարամետրերը օգտագործում են ոչ միայն տիպերի անուները փոխանցելու համար։ `...` այս օպերատորը աջից իր հերթին թույլ է տալիս պարամետրերը հանդես գան առանձին փոփոխականներ ( ինչպես ցույց է տրված ներքևի օրինակում `args...`-ի համար) ։

Կաղապարները փոփոխվող արժեքների դեպքում նույնպես հնարավոր է օգտագործել ռեկուրսիվ։ Այդպիսի օրինակ է `printf` ֆունկցիան.


```cpp
Void printf(const char*s)
{
while (*s) {
if (*s =='%'&&*(++s) !='%')
throw std::runtime_error("invalid format string: missing arguments");
        std::cout <<*s++;
    }
}

template<typename T, typename... Args>
void printf(constchar*s, T value, Args... args)
{
while (*s) {
if (*s =='%'&&*(++s) !='%') {
            std::cout << value;
++s;
            printf(s, args...); // շարունակում է հավաքումը 
/ / փոփոխականների , նույնիսկ այն դեպքում երբ *s == 0
return;
        }
        std::cout <<*s++;
    }
throw std::logic_error("extra arguments provided to printf");
}
```


Այս կաղապարը հանդիսանում է ռեկուրսիվ։ Ուշադրություն դարձրեք, որ `printf` ֆունկցիան կանչում է արդյունքը ինքն իր կամ բազային `printf`-ի այն դեպքում երբ `args...`-ն դատարկ է։
Չկա այնպիսի պարզ մեխանիզմ որով հնարավոր կլինի շրջանցել կաղապարների փոփոխվող արժեքների պարամետրերը։ Չնայած այդ բանին օգտագործելով փոփոխականների օպերատորը թույլ է տալիս շրջանցել այդ խնդիրը։
Օրինակ դասը հնարավոր է ներկայացնել հետևյալ կերպ.

```cpp
template<typename... BaseClasses>classClassName:public BaseClasses... {
public:

    ClassName (BaseClasses&&... base_classes) : BaseClasses(base_classes)... {}
};
```


 Փոփոխականների օպերատորը կրկնօրինակում է բոլոր տիպերը ծնող դասի `ClassName` հետևյալ կերպ, դասը պետք է ժառանգի բոլոր տիպերից որոնք նկարագրվել են կաղապարի պարամետրերում։
Բացի այդ կոնստրուկտորը պետք է ընդունի հղում բոլոր բազային դասերից, որպեսզի սկզբնական բազային-ծնող դասի `ClassName`-ի համար իրականցվի։
Կաղապարի պարամետրերը կարելի է վերահղվել։ Համատեղելով հղումնները `rvalue`-ի հետ ( նայեք վերևում ) հնարավոր է իրակնացնել վերահղում։


```cpp
template<typename TypeToConstruct> struct SharedPtrAllocator {
```



```cpp
template<typename ...Args> std::shared_ptr<TypeToConstruct> construct_with_shared_ptr(Args&&... params) {
return std::shared_ptr<TypeToConstruct>(new TypeToConstruct(std::forward<Args>(params)...));
    };
};
```


Հետևյալ կոդը իրականացվում է փոփոխականների վերաբաշխումը ըստ ցուցակի `TypeToConstruct` կոնստրուկտորում։`std::forward<Args>(params)` գրելաձևը թույլ է տալիս թափանցիկ վերահղել փոփոխականները կոնստրուկտորում, առանց հաշվի առնելու `rvalue` հատկանիշը։ Ֆունկցիան իքնաբերաբար դառնում է ցուցիչ `std::shared_ptr` որպեսզի ապահովի հիշողության կորստից։

Հնարավորություն կա համատեղել փոփոխականների թիվը հետևյալ կերպ։


```cpp
template<typename ...Args> struct SomeStruct {
staticconstint size =sizeof...(Args);
};
```


Այստեղ `SomeStruct<Type1, Type2>::size` հավասար է 2, իսկ `SomeStruct<>::size` հավասար է 0։

#### Նոր տողային լիտերալներ
**[[C++03]]** տրամադրում էր երկու տիպի տողային լիտերալներ։ Առաջինը տիպը իրենից ներկայացնում է երկու ապաթարցերում գրված զանգված որը ավարտվում է զրոյով (`null-terminated`) տիպը `const char`։ Երկրորդ տիպը սահմանվում է որպես **L""**, զանգված, որը ավարտվում է զրոյական սիմվոլով, տիպը `const wchar_t`, որտեղ `wchar_t` հանդիսանում է չսահմանված չափով և քերականությամբ սիմվոլ։ Ոչ մի տիպի լիտերալ չի սպասարկում `<span style="color:blue">UTF-8</span>`, `<span style="color:blue">UTF-16</span>`, կամ ցանկացած այլ տիպի `<span style="color:blue">Unicode</span>` կոդավորելուն։

`char` տիպի չափը այնքան փոքր է, որ կարողանա իր մեջ պահել 8 բիտ հիշողությամբ UTF-8 տիպի ցանկացած սիմվոլ, և այնքան մեծ որ կարողանա իր մեջ պահել ծրագրի կատարման ընթացքում ստացված ցանկացած սիմվոլ։

Գոյություն ունի երեք տիպի Unicode կոդավորում, որը աջակցում է **C++11** ստանդարտը, դրանք են. UTF-8, UTF-16 և UTF-32։ Որպես լրացում վերոնշյալ փոփոխություններին C++11 ստանդարտում ավելացել են ևս երկու սիմվոլային տիպ՝ `char16_t` և `char32_t`։ Նրանք օգտագործվում են `<span style="color:blue">UTF-16</span>` և `<span style="color:blue">UTF-32</span>` սիմվոլները պահելու համար։
Ներքևում ցույց է տրված թե ինչպես ստեղծել լիտերալներ այս բոլոր կոդավորումների համար։


```cpp
u8"I'm a UTF-8 string."
u"This is a UTF-16 string."
U"This is a UTF-32 string."
```


Առաջին տողում գրվածը սովորական `const char[]`: Երկրորդ տողինը —
`const char16_t[]`. Երրորդ տողինը — `const char32_t[]`.
Լիտերալների կառուցման համար ստանդարտ -ում, հաճախ անհրաժեշտ է լինում Unicode –ի կոդը դնել հենց տողում։ Դրա համար **C++11**-ը առաջարկում է հետևյալ գրելաձևերը.


```cpp
u8"This is a Unicode Character: \u2018."
u"This is a bigger Unicode Character: \u2018."
U"This is a Unicode Character: \U00002018."
```


\u-ից հետո պետք է թվերը լինեն տասնվեցական, պետք չէ օգտագործել պրեֆիքս 0x։ Ինդետիֆիկատոր \u նշանակում է 16-բիտային Unicode կոդ, իսկ 32-բիտային կոդով գրելու համար օգտագործվում է \U և 32-բիտային տասնվեցական թիվ։ Հնարավոր է գրել միայն ճշգրիտ Unicode կոդեր։ Օրինակ, կոդը այս ֆորմատով U+D800–U+DFFF արգելվում է, քանի որ նրանք վերապահված են փոխնակ զույգերի UTF-32-ում։
Երբեմն օգտակար է լինում խուսափել տողերի հետ ձեռքով աշխատել, հատկապես երբ օգտագործվում է լիտերալ XML տիպի ֆայլը, սկրիպտային ծրագրավորման լեզուներում, կամ կանոնավոր արտահայտություններում։ Այդ նպատակով C**++11**-ը ստանդարտը աջակցում է «հում(сырые)» տողային լիտերալներին։


```cpp
R"(The String Data \ Stuff " )"
R"delimiter(The String Data \ Stuff " )delimiter"
```


Առաջին դեպքում ամեն ինչ գտնվում է այս սիմվոլների մեջ "( և )", որը մասն է կազմում տողի։ Սիմվոլները " և \ պետք չէ էկրանին ցուցադրել։ Երկրորդ դեպքում `"delimiter`( սկիզբն է տողի և այն վերջանում է)`delimiter"`-ով։ `delimiter` տողը կարող է ունենալ 0-ից մինչև 16 երկարությամբ սիմվոլներ։ Այս տողը չի կարող պարունակել բացատանիշեր, ղեկավարվող սիմվոլները, '(', ')', կամ այս սիմվոլը '\' Օգտագործել այս տող-անջատիչները հնարավոր է օգտագործել ')' այս սիմվոլը «հում(сырые)» >> տողային լիտերալներում։ Օրինակ R"delimiter
`((a-z))delimiter"` համարժեք է `"(a-z)"`:

«հում(сырые)» տողային լիտերալները կարող են միավորվել ընդյլանված շարքի լիտերալների հետ ( պրեֆիքս L"") կամ ցանկացած այլ պրեֆիքս որը `Unicode` –ի լիտերալ է։


```cpp
LR"(Raw wide string literal \t (without a tab))"
u8R"XXX(I'm a "raw UTF-8" string.)XXX"
uR"*(This is a "raw UTF-16" string.)*"
UR"(This is a "raw UTF-32" string.)"
```


#### Տիպ <code>long long int</code>
Ամբողջ տիպ `long long int`-ը նշված է **[[C99]]** ստանդարտում և այն լայնորեն օգտագործվում է **[[C++]]**-ում, վերջապես այն հաստատել են **C++ 11** ատանդարտում։

#### Ստատիկ ախտորոշում
**C++11**-ը ունի երկու ձև ստատիկ ախտորոշման.
* Հատուկ անունի `static_assert` այն տալիս է սխալը կոմպիլատորին եթե փակագծերում արտահայտությունը կեղծ է։
* Գրադարան `type_traits`, որը պարունակում է կաղապար, տրամադրում է տեղեկատվություն հենց կոմպիլացիա ժամանակ։


```cpp
#include <type_traits>

template<class T>
void run(T *aData, size_t n)
{
static_assert(std::is_pod<T>::value, "Тип T должен быть простым.");
   ...
}
```


#### Աշխատանքը <code>sizeof</code>-ի հետ դասի տարրերի հետ առանց օբյեկտ ստեղծելու
**[[C++ 03]]** ստանդարտը թույլ էր տալիս օգտագործել `sizeof`-ը պարզ տիպերի և օբյեկտների համար։Բայց հետևյալ գրառումը չէինք կարող։


```cpp
struct SomeType
{
 OtherType member;
};
```



```cpp
sizeof(SomeType::member); //չի աշխատում '''[[C++03]]''', բայց ճիշտ է աշխատում '''C++11''':
```

Այս կանչի արդյունքում պետք է հաշվել `SomeType-ի` չափը։ **[[C++ 03]]**-ով կոդը կոմպիլացիա չէր լինում։ Իսկ **C++ 11**-ում այսպիսի գրելաձևը ընդունելի է, խնդիր չի առաջանում։

## Փոփոխություններ C++-ի ստանդարտ գրադարաններում
### Փոփոխություններ եղած բաղադրիչներում

* `std::set`-ում օգտագործվում է «հուշում» (hint). այստեղ «հուշման» իմաստը փոխվել է։ Առաջ այն տարրն էր մինչև ընթացիկը և հարց էր առաջանում ինչ անել երբ ունես մեկ տարր, իսկ հիմա այն ընթացիկից հետո է։
* C++֊-ն արդեն կարողանում է կոնստրուկտրը կանչել առանց հիշողություն հատկացնելու․ հետևյալ կերպ՝ `std::allocator_traits<>::construct()`։ Համապատասխանաբար առաջացել է նոր մեթոդ՝ `emplace`, որը տեղում է ստեղծում օբյեկտը։
* Ավելացել է նոր լեզվական հնարավորություններ **C++11** ստանդարտում։
* Ավելացվել են `cbegin` և `cend`, որոնցով երաշխավորված է ստեղծել հաստատուն իտերատորներ։ Հարմար է մետածրագրավորման համար, որում տիպերը ստեղծում են `auto`-ի միջոցով։
* Կոնտեյներներում, որոնք պահուստային հիշողություն են վերցնում, ավելացվել է `shrink_to_fit` ֆունկցիան։
* `std::list`-ից պահանջում են ավելին քան այն որ այն կատարվում է `O(n)` ժամանակում, հասել են նրան, որ այն կատարվում է հաստատուն ժամանակում։
* `std::vector`-ում ավելացվել է ֆունկցիա `data()`, որը կարողանում է դիմել միանգամից հիշողությանը։
* Արգելել են մի քանի `std::string`-ների միաժամանակ հղվել նույն հիշողության վրա։ Դրա շնորհիվ այժմ հնարավոր է միանգամից դիմել `front()`-ին, օրինակ փոխգործակցությունը `string`-ի և `WinAPI`-ի։

### Հեշ-աղյուսակներ
Երկար ժամանակ է, որ STL-ի ստանդարտի մեջ չէին ընդգրկվում `std::hash_set` և `std::hash_map` դասերը, այնինչ դրանք փաստացի իրականացվում էին գրեթե բոլոր կոմպիլյատորներում։ C++11 ստանդարտում այս դասերն ընդգրկված են ստանդարտի մեջ և հանդես են գալիս `unordered_set` և `unordered_map` անուներով։ Չնայած, ըստ հեշ-աղյուսակների էությանը ստանդարտը շատ թույլ չի տալիս մանևրելու, անուները նման են **[[C++]]**֊ի ոճին. ոչ թե «ինչպես են նրանք իրականացրել», և «ինչ են իրենցից ներկայացնում»։

### Կանոնավոր արտահայտություններ
Նոր գրադարանը, որը սահմանված է `<regex>` վերնագրային ֆայլում, ներառում է մի քանի նոր դասեր.

* Կանոնավոր արտահայտություններում ցույց են տրված է «օրինակ» դասերով, հետևյալ կերպ՝ `std::regex`։
* Արդյունքների որոնումը ցույց են տրված էկզեմպլիառ կաղապարներով հետևյալ կերպ՛ `std::match_results`։

`std::regex_search` այս ֆունկցան օգտագործում են փնտրելու համար։ Գտնելու և փոխելու համար օգտագործվում է `std::regex_replace` ֆունկցիան։ ֆունկցիան վերադարձնում է տողը հետո փոխարինում։
Ալգորիթմներ `std::regex_search` և `std::regex_replace` ստանում են մուտք գործել կանոնավոր արտահայտություններ և տողեր, վերադարձնում են արդյունքը էկզեմպլիառի տեսքով `std::match_results`:

Օրինակ օգտագործենք `std::match_results`.


```cpp
constchar*reg_esp ="[ ,.\\t\\n;:]"; // ցուցակը անջատիչ սիմվոլների

// նույն հնարավոր է անել օգտագործելով "հում(сырые)" տողերը։
// const char *reg_esp = R"([ ,.\t\n;:])";

std::regex rgx(reg_esp); // 'regex' – սա էկզեմպլառ է կաղապար դասով
// 'basic_regex' կաղապար է 'char' պարամետրով։
std::cmatch match; // 'cmatch' - սա էկզեմպլառ է կաղապար դասով

// 'match_results' կաղապար է 'const char *' պարամետրով։
constchar*target ="Unseen University - Ankh-Morpork";

// Ֆիքսում է բոլոր 'target' բառերը տողում անջատելով սիմվոլներով 'reg_esp':
if( std::regex_search( target, match, rgx ) ) {
// եթե բառ է, անջատիչ սիմվոլը գտնվում է տողում։

constsize_t n = match.size();
for( size_t a =0; a < n; a++ ) {
        std::string str( match[a].first, match[a].second );
        std::cout << str <<"\n";
    }
}
```


## Ծանոթագրություններ