C++ 14
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 ին։
Տեսակ | ISO standard edition? և programming language specification? |
---|---|
Ենթադաս | C++ |
Կատարման ձև | կոմպիլյացիա |
Առաջացել է | դեկտեմբերի 15, 2014 |
Ստեղծող | Բյերն Ստրաուստրուպ |
Տիպիզացիա | ստատիկ, խիստ |
Հիմնական իրականացումներ | g++, clang++ |
Հիմքի վրա է | C++03 |
Ներշնչվել է | C, Simula |
Ներշնչել է | Java |
Նախորդ | C++11 |
Հաջորդ | C++17 |
Անվանված է | 2014 |
Կայք | iso.org/standard/64029.html(անգլ.) |
Քանի որ ստանդարտի մշակումը երկարատև էր, իսկ վերջնական տարբերակի հրապարակման թիվը հստակ չէր, մշակման ընթացքում օգտագործվում էր «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
ֆունկցիան կարող է ունենալ հետևյալ տարրերը։
- Ցանկացած հայտարարում բացի
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
և այլն )։
Այսպիսի հայտարարումները և սահմանումները պատկանում է կաղապարների կանոններին։
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
, որոնք վերադաձնում են կոնստանտ իտերատորներ դիապազոնի սկզբի և վերջի վրա։