Բյորն Ստրաուստրուպը C++ ծրագրավորման լեզվի ստեղծողը
**C++14** —վերջին ստանդարտի ոչ պաշտոնական անվանումը C++ ISO/IEC JTC1 է (ամբողջական անվանումը՝ «*International Standard ISO/IEC 14882:2014(E) Programming Language C++*». C++14 ը կարելի է դիտարկել որպես C++11-ի փոքրիկ ընդլայնում, որը հիմնականում պարունակում է սխալների ուղղում և որոշակի բարելավում։ Նոր ստանդարտը մշակող հանձնաժողովը N3690 սևագիրը թողարկեց 2013 թվականի մայիսի 15-ին։ N3936 սևագրի աշխատող տարբերակը թողարկվեց 2014 թվականի մարտի 2-ին, քվեարկության վերջնական փուլը ավարտվեց 2014 թվականի օգոստոսի 15-ին, իսկ արդյունքները ( միաձայն հավանությամբ ) հայտարարվեցին 2014 թվականի օգոստոսի 18 ին։

Քանի որ ստանդարտի մշակումը երկարատև էր, իսկ վերջնական տարբերակի հրապարակման թիվը հստակ չէր, մշակման ընթացքում օգտագործվում էր «C++1y» անունը, ինչպես C++11-ը, մինչ թողարկումը անվանում էին «C++0x» ( այս տարբերակի թողարկումը սպասվում էր մինչ 2010 թվականը)։

Ներքևում նկարագրվող լեզվի հնարավորությունները համապատասխանում են N3797 աշխատող սևագրին։ Հնարավոր է ստանդարտի վերջնական տարբերակից մի փոքր տարբերվեն։

Լեզվում կատարված փոփոխություններ
--------------------------------

Այս բաժնում ներկայացված են C++14 լեզվի միջուկի նոր հնարավորությունները։

### Վերադարձվող արժեքի տիպի դուրսբերումը ֆունկցիայի համար

C++11 թույլ է տալիս դուրս բերել լյաբդա-ֆունկցիաների վերադարձվող արժեքի տիպը, վերադարձվող արտահայտության տիպից։ C++14-ում այդ հնարավորությունը ընդգրկում է բոլոր ֆունկցիաները։ Նոր ստանդարտը լյաբդա-ֆունկցիաների համար նաև նկարագրում է տիպերի դուրսբերումը `return expression`-ից տարբերվող դեպքերում։

Վերադարձվող արժեքի տիպի ավտոմատ դուրս բերման համար ֆունկցիայի վերադարձվող արժեքի տիպը պետք է հայտարարված լինի `auto`, բայց ի տարբերություն նախորդ ստանդարտի ֆունկցիայի հայտարարման վերջում վերադարձվող տիպը բացահայտ նշելու կարիք չկա։

```
auto DeduceReturnType(); // տիպի վերադարձվող արժեքը հայտնի կլինի ավելի ուշ

```

Եթե ֆունկցիայի մարմնի տարբեր մասերից վերդարձնում է մի քանի արտահայտություններ, ապա այդ արտահայտություններից վերադարձվող տիպը պետք է նույնը լինի բոլոր արտահայտությունների համար։ Ֆունկցիաները՝ որոնք ավտոմատ կերպով են վերադարձնում տիպը, հնարավոր է օգտագործել նախնական հայտարարումը, սակայն հնարավոր է օգտագործել սահմանելուց հետո։ Այս սահմանումների թարգմանությունը պետք է հասանելի լինեն նույն տեղում որտեղ, որ օգտագործում են։

```
auto Correct(int i)
{
 if (i == 1)
 return i; // Ինչպես օրինակում վերադարձվող տիպը int է
 else
 return Correct(i-1)+i; // Այժմ հնարավոր է կանչել 
}

auto Wrong(int i) {
 if(i != 1)
 return Wrong(i-1)+i; // հարմար տեղ չէ ռեկուրսիա համար:Չկա նախորդ կանչը։
 else
 return i; // վերադարձվող տիպը կլինի int 
}

```

### Այլընտրանքային եղանակով տիպի դուրս բերումը հայտարարելու ժամանակ

C++11-ում հնարավոր էր տիպը դուրս բերել երկու եղանակով։ `auto`-ն հնավարություն է տալիս ստեղծել փոփոխականներ որոնց տիպը հիմնականում որոշվում է այն արտահայտությունից որը վերագրվում է։ `decltype`-ը հնարավորություն է տալիս տիպը որոշել կամայական արտահայտությունից։ Մեծ մասամբ `auto`-ն վերադարձնում է ոչ հղումային տիպ, եթե մշակված լիներ որպես `std::remove_reference`, ապա կվերադարձներ հղումային տիպի `auto&&`։ Այդուհանդերձ `decltype`-ի տիպը կարող է լինել ինչպես հղումային այնպես էլ ոչ հղումային կախված արտահայտությունից։

```
int i;
int&& f();
auto x3a = i; // decltype(x3a) - int
decltype(i) x3d = i; // decltype(x3d) - int
auto x4a = (i); // decltype(x4a) - int
decltype((i)) x4d = (i); // decltype(x4d) - int&
auto x5a = f(); // decltype(x5a) - int
decltype(f()) x5d = f(); // decltype(x5d) - int&&

```

```
C++14-ում ավելացվել է decltype(auto)։ decltype-ի այս գրելաձևը հնարավորություն է տալիս օգտագործել auto-ի հայտարարում։ decltype(auto) գրելաձևը հնարավոր է օգտագործել վերադարձվող արժեքի տիպը որոշելու համար, եթե ցույց տանք decltype(auto)-ի հետ auto-ն որտեղ ֆունկցիա արժեքը վերադարձնում է տիպը։
```

```
int i;
int&& f();
auto x3a = i; // decltype(x3a) is int
decltype(auto) x3d = i; // decltype(x3d) is int
auto x4a = (i); // decltype(x4a) is int
decltype(auto) x4d = (i); // decltype(x4d) is int&
auto x5a = f(); // decltype(x5a) is int
decltype(auto) x5d = f(); // decltype(x5d) is int&&
auto x6a = { 1, 2 }; // decltype(x6a) is std::initializer\_list<int>
decltype(auto) x6d = { 1, 2 }; // error, { 1, 2 } is not an expression
auto \*x7a = &i; // decltype(x7a) is int\*
decltype(auto)\*x7d = &i; // error, declared type is not plain

```

### Հաստատուն արտահայտությունների սահմանափակումների նվազեցում

C++11-ում ներկայացված է `constexpr` ֆունկցիա հասկացությունը։ Այս հասկացությունը հնարավորություն է տալիս ֆունկցիան իրականացնել կոմպիլացիա ժամանակ։ Վերադարձված արժեքները կարող են օգտագործվել այնպիսի արտահայտություններում որտեղ արտահայտությունը հաստատուն է, օրինակ. որպես կաղապարի փոփոխական։ Այնուհանդերձ constexpr ֆունկցիան C++11-ում կարող է վերադարձնել միայն մեկ արժեք (ինչպես նաև `static_assert`-ը և մի քանի այլ ֆունկցիաներ )։
C++ 14 –ում այդ երևույթների մի մասը հանած է։ Հիմա `constexpr` ֆունկցիան կարող է ունենալ հետևյալ տարրերը։

* Ցանկացած հայտարարում բացի

1. `static` կամ `thread_local` փոփոխականներ
2. հայտարարել փոփոխակաները առանց սկզբնավորելու

* Պայմանական արտահայտությունների ճյուղավորումը `if` և `switch`
* Բոլոր ցիկլիկ օպերատորների այդ թվում `for`-ի միջակայքերի համար
* Արտահայտությունները, որոնք փոխել են օբյեկտի արժեքը և եթե այդ օբյեկտները ստեղծվել են constexpr հրամանով, ապա սա ներառում է կանչեր ցանկացած ոչ `constconstexpr`, ոչ ստատիկ ֆունկցիայի անդամների համար։

goto-արտահայտությունում թույլ չի տալիս constexpr ֆունկցիաները C++14:

Սահմանափակումները ոչ `constexpr` ֆունկցիաների համար մնում է ուժի մեջ։ Այսպիսով եթե օգտագործում ենք `for` հրամանը միջակայքերի համար, ապա `begin` և `end` ֆունկցիաները կոնտեյնեռների համար պետք է լինեն գերբեռնված որպես `constexpr`։ Որպես կառուցողաղկան տիպ `std::initializer_list` ֆունկցիաները `begin`/`end` սահմանված են որպես `constexpr` ինչպես լոկալ, այնպես էլ ընդհանուր դեպքում։

Բացի այդ C ++ 11-ի բոլոր ոչ ստատիկ մեթոդները հայտարարել են ինչպես `constexpr`, վերջերս համարում էին `const`-ֆունկցիան դիմում է `this`-ին, բայց հիմա այդ սահմանափակումը հանած են, ոչ ստատիկ մեթոդները կարող են լինել ոչ `const`։ Այնուհանդերձ, ինչպես առաջ էր նշվում ոչ `const constexpr` մեթոդը կարող է փոխել դասսը այն դեպքում երբ այդ արտահայտությունը ստեղծվել է հաստատուն արտահայտության ստեղծման ժամանակ։

### Փոփոխականների կաղապարներ

C++-ի նախորդ տարբերակներում կաղապարները սահմանված էր միայն ֆունկցիաների և դասերի համար։ C++14-ը թույլ է տալիս ստեղծել կաղապար փոփոխականներ։ Օրնակ պի թվի ներկայացումը կաղապար փոփոխականով, կաղապար փոփոխականին տալով պի-ն ստանում ես նրա արժեքը, ամբողջ տիպի համար այն կլինի 3 (ավելի ճշգրիտ արժեք ստանալու համար տիպը պետք է ընտրել `float`, `double` կամ `long double` և այլն )։
Այսպիսի հայտարարումները և սահմանումները պատկանում է կաղապարների կանոններին։

```
template<typname T>
 constexpr T pi = T(3.1415926535897932385);

template<typname T>
T circular\_area(T r)
 {
 return pi \* r \* r; 
}

```

### Դասերի համախառն սկզբնարժեքավորում դաշտերի սկզբնարժեքավորողներով

C++ 11-ում ավելացվել են դասերի դաշտերի սկզբնարժեքավորողներ- արտահայտություններ, կիրառվում է դաշտերի վրա դասի մակարդակում, եթե կոնստրուկտորը ինքնուրույն չի սկզբնարժեքավորում։ Ագրեգատների ինիցիալիզացումը փոփոխվել է, որպեսզի բացահայտորեն բացառի անդամների ինցիալիզացիաները, որովհետև դրանց համար ագրեգատայինինիցիալիզացիան անհար է։
C++14-ը հանում է այդ սահմանափակումը և ընդլայնում է դասերի համախառն սկզբնարժեքավորումը դաշտերի սկզբնարժեքավորողներով։ Եթե ձևավոր փակագծերի մեջ եղած սկզբնարժեքավորողների ցուցակը տվյալ արգումենտի համար արժեք չի հատկացնում, ապա այդ գործը իր վրա է վերցնում դաշտի սկզբնարժեքավորողը։

### Երկուական թվերի լիտերալներ

Թվային լիտերալները C++14 ում կարելի է հայտարարել երկուական տեսքով։ Գրելաձևը օգտագործում է 0բ կամ 0Բ նախդիրները։ Նմանատիպ գրելաձև օգտագործվում է նաև Java, Python, Perl и D լեզուներում։

### Կարգերի բաժանիչներ

C++14 –ում կարելի է օգտագործել ապաթարց թվային լիտերալներում կարգերի առանձնացման համար։ Որոշ դեպքերում դա հեշտացնում է մեծ հաստատունների ընկալումը և հեշտացնում է կոդի ընթերցելիությունը։

```
auto integer\_literal = 1’000’000;
auto floating\_point\_literal = 0.000’015’3;
auto binary\_literal = 0b0100’1100’0110;
auto silly\_example = 1’0’0’000’00;

```

### Ընդհանրացված լյամբդա-ֆունկցիաներ

C++11-ում լյամբդա-ֆունկցիաների պարամետրերը անհրաժեշտ է հայտարարել նշելով կոնկրետ տիպը։ C++14-ը հանում է այդ սահմանափակումը և թույլատրում է լյամբդա-ֆուկցիաների հայտարարումը `auto` հատուկ բառով։

```
auto lambda = [](auto x, auto y)
{
 return x + y;
};

```

Ընդհանրացված լյամբդա-ֆունկցիաների պարամետրերի տիպերի դուրսբերումը կատարվում է `auto`-փոփոխականների տիպերի դուրսբերման օրենքներով (բայց ամբողջովին նույնը չէ)։ Վերևում ներկայացված կոդը համարժեք է հետևյալին.

```
struct unnamed\_lambda
{
 template auto operator()(T x, U y) const 
 {
 return x + y;
 } 
};
auto lambda = unnamed\_lambda();

```

### Լյամբդա-ֆունկցիաների արտահայտությունների ընդունումը

Լյամբդա-ֆունկցիաները C++11-ում թույլատրում են ընդունել ներքին տեսանելիության տիրույթում հայտարարված փոփոխականները, հղման կամ արժեքի փոխանցման ճանապարհով։ Դա նշանակում է որ չի կարելի արժեքով ընդունել միայն տեղափոխում թույլատրող( բայց կրկնօրինակում չթույլատրող ) տիպի փոփոխականները։ C++14-ը թույլատրում է ընդունել ցանկացած արտահայտությամբ սկզբնարժեքավորված փոփոխականներ։ Դրա շնորհիվ կարելի է ընդունել փոփոխականներ արժեքի տեղափոխումով և հայտարարել ավելի բարձր տեսանելույան տիրույթում չհայտատրարված անունով փոփոխականներ։
Արտահայտությունների ընդունումը իրականավում է սկզբնարժեքավորողների օգնությամբ

```
auto lambda = [value = 1]
{
 return value;
};

```

`lambda` լյամբդա-ֆունկցիան կվերադարձնի 1, քանի որ value պարամետրի համար աշխատել է համապատասխան սկզբնարժեքավորողը։ Ընդունված պարամետրի տրպը դուրս է բերվում սկզբնարժեքավորողի տիպից `auto` հատուկ բառի հայտարարության համաձայն։

`lambda` լյամբդա-ֆունկցիան կվերադարձնի 1, քանի որ value պարամետրի համար աշխատել է համապատասխան սկզբնարժեքավորողը։ Ընդունված պարամետրի տրպը դուրս է բերվում սկզբնարժեքավորողի տիպից `auto` հատուկ բառի հայտարարության համաձայն։

```
std::unique\_ptr ptr(new int(10));
auto lambda = [value = std::move(ptr)]
{
 return \*value;
};

```

### Ատրիբուտ deprecated

`deprecated` ատրիբուտը հնարավորություն է տալիս որոշակի երևույթներ նշել որպես հնեցված։ Այդպիսի երևույթների օգտագործման ժամանակ, կոմպիլյացիայի ընթացքում դուրս է բերվում զգուշացում։ deprecated ատրիբուտի արգումենտ կարող է հանդիսանալ տողային լիտեռալ, որը կբացատրի հնեցման պատճառը և/կամ դրա հնարավոր ալտերնատիվը։

```
[[deprecated]] int f();

[[deprecated("g()ապահով չէ. օգտագործեք h(), g() փոխարեն" ) ] ]
void g( int& x );

void h( int& x );

void test() {
 int a = f(); // warning: 'f' is deprecated
 g(a); // warning: 'g' is deprecated: g() ապահով չէ. օգտագործեք h(), g() փոխարեն
}

```

Ստանդարտ գրադարանի նոր ֆունկցաիներ
----------------------------------

### Բաժանվող մյուտեքսներ և կանխարգելում

C++14 ստանդարտում ավելացված են բաժանված (shared) մյուտեքսներ և նոր կանխարգելման եղանակ մյուտեքսների համար։

### Չսահմանված որոնում կոնտեյներներում

C++ ստանդարտում գրադարնում սահմանված են չորս տեսակի ասոցատիվ դաս-կոնտեյներ։ Այդ դասերը հնարավորություն են տալիս արժեքների փնտրում հիմնվելով այդ դասի տիպի վրա։`map` կոնտեյներում նշվում է բանալիի և արժեքի տիպերը, իսկ որոնումը տեղի է ունենում բանալիով և վերադարձնում է արժեքը։ Ամեն դեպքում որոնումը կատարվում է ըստ բանալու՝ լինի դա բանալին `map`-ում թե արժեքը `set`-ում։ C++14 ստանդարտը թույլ է տալիս ստեղծել կամայական տիպի ասոցատիվ կոնտեյներներ. պայմանով, որ դրանք ունենան գերբեռնված համեմատման օպերատոր, որի միջոցով հնարավոր լինի համեմատել տվյալ տիպի օբյեկներ։ Սա հնարավորություն է տալիս `std::string` բանալու տիպով `map`-ում կատարել որոնում `const char*` տիպի օբյեկտի օգնությամբ օգտագործելով գերբեռնված `operator<`։Չսահմանված որոնումը թույլ է տալիս միայն այն ժամանակ, երբ կոնտեյներին փոխանցված կոմպարատորը ինքը թույլ է տալիս նման որոնումը։ Ստանդարտ գրադանի `std::less` և `std::greater` թույլ են տալիս կատարել չսահմանված որոնում։

### Ստանդարտ օգտագործման լիտերալներ

C++11 ստանդարտում նկարագրված է օգտագործողի կողմից սահմանվող լիտեռալային նախաբառերի սահմանման գրելաձև, բայց դրանցից ոչ մեկ չի օգտագործվում ստանդարտ գրադարանում։ C++14 ավելացնում է հետևյալ ստանդարտ լիտեռալները.

* «s»` std::basic\_string տարբեր տիպերի համար
* «h», «min», «s», «ms», «us», «ns» ՝ std::chrono::duration տիպի ժամանակային լիտեռալների համար

```
string str = "hello world"s;
chrono::duration dur = 60s;

```

Երկու «s» լիտեռալները չեն ազդում իրար վրա, քանի որ տողային լիտեռալը աշխատում է միայն տողային լիտեռալի հետ, ժամանակայինը միայն թվերի։

### Խմբակների հասցեավորումը տիպերով

`std::tuple`-ը, որը ավելացվել է C++11 ստանդարտում թույլ է տալիս միմյանց կցել մի քանի տարբեր տիպերի արժեքներ որոնք կինդեքսավորվեն կոմպիլյացիայի ժամանակ։C++14 ընդլայնում է խմբակների ֆունկցիոնալությունը թույլ տալով դրանց էլեմենտներին դիմել ոչ միայն ինդեքսով այլև տիպի միջոցով։ Եթե խմբակը պարումնակում է նույն տիպի մի քանի օբյեկտներ ապա տիպի միջոցով դրա անդամներին դիմելը կբերի կոմպիլյացիայի սխալի։

```
tuple<string, string, int> t("foo", "bar", 7);
int i = get<int>(t); // i == 7
int j = get<2>(t); // նույն է ինչ նախորդ տողը։ j == 7
string s = get<string>(t); // սխալ է՝ անորոշությունների պատճառով

```

### Ստանդարտ գրադարանի այլ փոփոխություններ

`std::make_unique` կարելի է օգտագործել ինչպես `std::make_shared`, `std::unique_ptr` տիպի օբյեկտների համար։ `std::integral_constant`-ի համար ավելացվել է գերբեռնված `operator()`, որը կոնստանտ արժեք է վերադարձնում։ `std::begin/std::end` գլոբալ ֆունկցիաների անալոգիայով ավելացվել է `std::cbegin/std::cend`, որոնք վերադաձնում են կոնստանտ իտերատորներ դիապազոնի սկզբի և վերջի վրա։

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