C++ 14

[մինի|[Բյորն Ստրաուստրուպը 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`, բայց ի տարբերություն նախորդ ստանդարտի ֆունկցիայի հայտարարման վերջում վերադարձվող տիպը բացահայտ նշելու կարիք չկա։

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


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

```cpp
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`-ի տիպը կարող է լինել ինչպես հղումային այնպես էլ ոչ հղումային կախված արտահայտությունից։

```cpp
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`-ն որտեղ ֆունկցիա արժեքը վերադարձնում է տիպը։

```cpp
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` ֆունկցիան կարող է ունենալ հետևյալ տարրերը։
* Ցանկացած հայտարարում բացի
# `static` կամ `thread_local` փոփոխականներ
# հայտարարել փոփոխակաները առանց սկզբնավորելու
* Պայմանական արտահայտությունների ճյուղավորումը `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` և այլն )։
Այսպիսի հայտարարումները և սահմանումները պատկանում է կաղապարների կանոններին։

```cpp
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 –ում կարելի է օգտագործել ապաթարց թվային լիտերալներում կարգերի առանձնացման համար։ Որոշ դեպքերում դա հեշտացնում է մեծ հաստատունների ընկալումը և հեշտացնում է կոդի ընթերցելիությունը։

```cpp
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` հատուկ բառով։

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

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

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


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

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

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

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

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


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

```cpp
[[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 տիպի ժամանակային լիտեռալների համար

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

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

```cpp
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`, որոնք վերադաձնում են կոնստանտ իտերատորներ դիապազոնի սկզբի և վերջի վրա։

Կատեգորիա:C++