Přeskočit na obsah

C++14

Z Wikipedie, otevřené encyklopedie
Verze jazyka C++

C++14 je verze ISO/IEC 14882 normy programovacího jazyka C++. Měla být malým rozšířením C++11 obsahujícím především opravy chyb a drobná vylepšení. Její schválení bylo ohlášeno 18. srpna 2014[1] a publikována byla jako ISO/IEC 14882:2014 v prosinci 2014.[2]

Protože starší revize normy C++ se výrazně opozdily, byla verze C++17 někdy označována „C++1y“, podobně jako jako byla verze C++11 označována „C++0x“. V roce 2017 byla nahrazena normou C++17.

Nové vlastnosti jazyka

[editovat | editovat zdroj]

K jádru jazyka C++ byly ve verzi C++14 přidány následující vlastnosti:

Vyvozování návratového typu funkce

[editovat | editovat zdroj]

C++11 umožňuje odvodit návratový typ lambda funkce z typu výrazu použitého v příkazu return. C++14 tuto schopnost rozšiřuje na všechny funkce. Pro lambda funkce lze návratový typ vyvodit i pro funkce, které nejsou tvaru return výraz.[3]

Pro použití vyvozování návratového typu musí být funkce deklarována s návratovým typem auto, a nesmí být použit koncový specifikátor návratového typu zavedený v C++11:

auto DeduceReturnType(); // návratový typ, který se má odvodit.

Pokud je v implementaci funkce použito několik návratových výrazů, pak se ze všech musí odvodit stejný typ.[4]

Funkce, u nichž je použito vyvozování návratového typu, mohou být deklarovány dopředně, ale dokud nebyly definovány, nemohou být použity. Jejich definice musí být dostupná v té kompilační jednotce, v níž jsou použity.

Funkce tohoto typu mohou používat rekurzi, ale rekurzivní volání se může objevit až po příkazu return v definici funkce:[4]

auto Correct(int i)
{
  if (i == 1)
    return i; // návratový typ odvozený jako int

  return Correct(i-1)+i; // Rekurzivní volání je zde v pořádku
}

auto Wrong(int i)
{
  if (i != 1)
    return Wrong(i-1)+i; // Tomuto volání nepředchází příkaz return -> chyba

  return i; // návratový typ odvozený jako int
}

Alternativní vyvozování typu při deklaraci

[editovat | editovat zdroj]

C++11 definovalo dvě metody vyvozování typu: auto umožňuje deklarovat proměnnou, jejíž typ se odvodí z typu výrazu, kterým je inicializována. Operátor decltype vrací typ daného výrazu při překladu. Tyto dvě metody však vyvozují typ různými způsoby. Konkrétně auto nikdy nevyvodí referenci, jako při použití std::decay, zatímco auto&& vždy vyvodí referenci. Operátor decltype lze však přimět k vyvození reference nebo nereference na základě kategorie hodnoty výrazu a povahy výrazu:[5][3]

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

C++14 umožňuje použít decltype(auto), což umožňuje, aby deklarace s auto používaly stejná pravidla, jaká používá decltype.

Syntaxe decltype(auto) může být použita také s vyvozováním návratového typu funkce.[4]

Uvolnění omezení pro constexpr

[editovat | editovat zdroj]

Verze C++11 zavedla koncept funkcí deklarovaných s constexpr, u nichž lze hodnotu zjistit v době překladu. Návratovou hodnotu takové funkce lze použít v konstantním výrazu, např. v celočíselném argumentu šablony. V C++11 mohly funkce s constexpr obsahovat pouze jediný výraz, které je vracené (stejně jako static_assert a několik dalších deklarací).

C++14 tato omezení uvolňuje. Funkce deklarované s constexpr mohou nyní obsahovat:[3]

  • libovolné deklarace kromě:
    • deklarací proměnných se static nebo thread_local
    • deklarací proměnných bez inicializátorů
  • příkazů podmíněného větvení if a switch
  • libovolných příkazů cyklu, včetně cyklu přes rozsah
  • výrazy, které mění hodnotu objektu, pokud životnost tohoto objektu začala ve funkce v konstantním výrazu; sem patří volání libovolných nestatických členských funkcí bez const nebo constexpr.

Ve funkcích deklarovaných s constexpr jsou zakázány příkazy goto.

Verze C++11 také vyžaduje, aby všechny nestatické členské funkce, které byly deklarovány s constexpr byly také implicitně deklarovány s const podle this. V C++14 bylo toto omezení odstraněno; nestatické členské funkce nemusí být const.[6] Kvůli výše uvedenému omezení však constexpr členské funkce bez const mohou měnit členy třídy, pouze pokud životnost tohoto objektu začala ve vyhodnocování konstantního výrazu.

Šablony proměnných

[editovat | editovat zdroj]

V předchozích verzích C++ bylo možné definovat šablony pouze pro funkce, třídy nebo typové aliasy. C++14 umožňuje vytváření šablon proměnných. V návrhu je uveden příklad proměnné pi, kterou lze číst pro získání hodnoty Ludolfova čísla různých typů (například 3, pokud se čte jako celočíselný typ; lepší hodnotu lze získat pro typy float, double nebo long double).

Pro takové deklarace a definice platí obvyklá pravidla pro šablony, včetně specializací.[7][8]

template<typenameT>
constexpr T pi = T(3.141592653589793238462643383);

// Obvyklý způsob specializace:
template<>
constexpr const char* pi<const char* > = pi;

Inicializace členů agregátů

[editovat | editovat zdroj]

Verze C++11 přidala implicitní inicializátory členů, výrazy, které se použijí na členy v rozsahu platnosti třídy, pokud konstruktor neinicializuje člen samotný. Definice agregátů byla změněna tak, aby výslovně vylučovala všechny třídy s inicializátory členů; proto se nesmějí používat pro inicializaci agregátů.

C++14 toto omezení uvolňuje,[3] a umožňuje agregátní inicializaci takových typů. Pokud inicializační seznam uzavřený ve složených závorkách neobsahuje hodnotu určitého argumentu, postará se o ni členský inicializátor.[9]

Binární literály

[editovat | editovat zdroj]

Numerické literály lze v C++14 zapisovat ve dvojkové soustavě[3] s použitím předpony 0b nebo 0B, která se používá i v jiných jazycích, např. v Javě, C#, Swift, Go, Scala, Ruby, Python, OCaml, a jako neoficiální rozšíření v některých překladačích jazyka C již od roku 2007.[10]

Oddělovače číslic

[editovat | editovat zdroj]

V C++14 lze používat znak apostrof jako oddělovač číslic v číselných literálech, jak v celočíselných, tak pro čísla s pohyblivou řádovou čárkou.[11] Jeho použití může člověku usnadňovat analýzu dlouhých čísel:

auto integer_literal = 1'000'000; // milion
auto floating_point_literal = 0.000'015'3; // patnáct miliontin
auto binary_literal = 0b0100'1100'0110; // lze i skupiny po čtyřech číslicích
auto a_dozen_crores = 12'00'00'000;

Obecné lambda funkce

[editovat | editovat zdroj]

V C++11 musí být parametry lambda funkcí deklarovány s konkrétními typy. C++14 tento požadavek uvolňuje a dovoluje, aby parametry lambda funkcí byly deklarovány se specifikátorem typu auto.[7]

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

Co se týče vyvozování typu auto, generické lambda funkce se řídí pravidly vyvozování argumentů šablon (která jsou podobná, ale ne ve všech směrech totožná[ujasnit]). Výše uvedený kód je ekvivalentní s:[12]

struct
{
  template<typenameT, typename U>
    auto operator()(T x, U y) const {return x + y;}
} lambda{};

Generické lambda funkce jsou v zásadě šablonové lambda funktory.

Lambda capture výrazy

[editovat | editovat zdroj]

Lambda funkce v C++11 zachycují proměnné deklarované v obklopujícím rozsahu platnosti kopírováním hodnot nebo referencí. To znamená, že hodnotové členy lambda funkce nemohou typy umožňující pouze přesun.[13] C++14 umožňuje zachycené členy inicializovat libovolnými výrazy. To umožňuje jak zachycení pomocí přesunu hodnoty, tak deklaraci libovolných členů lambda funkce, aniž by v obklopujícím rozsahu platnosti existovala odpovídající pojmenovaná proměnná.[7]

To se provádí pomocí inicializačního výrazu:

auto lambda = [hodnota = 1] {return hodnota;};

Lambda funkce lambda vrací hodnotu 1, na kterou byla proměnná hodnota inicializována. Deklarované zachycení vyvozuje typ z inicializačního výrazu, jako kdyby bylo použito auto.

To lze použít pro zachycení přesunem, použitím standardní funkce std::move:

std::unique_ptr<int> ptr(nový int(10));
auto lambda = [hodnota = std::přesun(ptr)] {return *hodnota;};

Atribut deprecated

[editovat | editovat zdroj]

Atribut deprecated umožňuje označit entitu jako deprecated (nedoporučovaná). Takovou entitu lze stále používat, ale při překladu může způsobit výpis varování, aby programátor věděl, že s jejím použitím se v budoucnu nepočítá. Atribut deprecated může být doplněn textem, který může obsahovat odůvodnění a napovídat, jakou použít náhradu.

[[deprecated]] int f();

[[deprecated("g() is thread-unsafe. Use h() instead")]]
void g( int& x );

void h( int& x );

void test()
{
  int = f(); // varování: 'f' is deprecated
  g(a); // varování: 'g' is deprecated: g() is thread-unsafe. Use h() instead
}

Nové vlastnosti standardní knihovny

[editovat | editovat zdroj]

Sdílené mutexy a zamykání

[editovat | editovat zdroj]

C++14 přidává sdílený časovaný mutex a doprovodný sdílený zámek.[14][15]

Heterogenní vyhledávání v asociativních kontejnerech

[editovat | editovat zdroj]

Standardní knihovna C++ definuje čtyři třídy asociativních kontejnerů. Tyto třídy umožňují uživateli vyhledat hodnotu podle klíče daného typu. Kontejnery v jejichž názvu je slovo „anglicky map (zobrazení)“ umožňují uživateli zadat jak klíč tak hodnotu, přičemž vyhledávání se provádí podle klíče a vrací hodnotu. Vyhledávání se však vždy provádí podle určitého typu klíče, ať je to klíč jako u zobrazení nebo samotná hodnota jako u množin.

C++14 umožňuje vyhledávat podle libovolného typu, pokud pro něj existuje operátor porovnání.[16] To umožňuje porovnávat klíče typu std::string s řetězci typu const char* nebo jiného typu, pro který existuje přetížení operátoru <. Také je užitečné indexovat složené objekty v std::set hodnotou jediného členu bez nutnosti vytvářet nastrčený objekt při používání funkce find (nebo např. nutné vytvářet celou struct Osoba pro hledání osoby podle jména).

Kvůli zachování zpětné kompatibility je heterogenní vyhledávání povoleno pouze tehdy, když to komparátor přiřazený k asociativnímu kontejneru umožňuje. Pro usnadnění heterogenního hledání bylo ve standardní knihovně provedeno rozšíření tříd std::less<> a std::greater<>.[17]

Standardní uživatelem definované literály

[editovat | editovat zdroj]

C++11 definovalo syntaxi pro uživatelem definované sufixy literálů, ale standardní knihovna je nepoužívala. C++14 přidává následující standardní literály:[16]

  • s, pro vytváření různých typů založených na std::basic_string.
  • h, min, s, ms, us, ns, pro vytváření odpovídajících std::chrono::duration časových intervalů.
  • if, i, il, pro vytváření odpovídajících imaginárních čísel typu std::complex<float>, std::complex<double> nebo std::complex<long double>.
auto str = "hello world"s; // z auto se vyvodí string
auto dur = 60s;            // z auto se vyvodí chrono::seconds
auto z = 1i;               // z auto se vyvodí complex<double>

Existence dvou literálových sufixů s nepůsobí kolizi, protože jeden je řetězcový a druhý číselný.[18]

Adresování prvků n-tic pomocí typu

[editovat | editovat zdroj]

Typ std::tuple zavedený v C++11 umožňuje indexovat n-tici typovaných hodnot pomocí celočíselného indexu, jehož hodnota je konstanta známá v době překladu. C++14 umožňuje také výběr hodnoty z n-tice podle typu.[16] Pokud má n-tice více než jeden prvek daného typu, bude při překladu ohlášena chyba:[19]

tuple<string, string, int> t(foo, bar, 7);
int i = get<int>(t);       // i == 7
int j = get<2>(t);         // Totéž: j == 7
string s = get<string>(t); // Chyba při překladu kvůli nejednoznačnost

Menší vlastnosti knihovny

[editovat | editovat zdroj]

Pro objekty std::unique_ptr lze používat std::make_unique jako std::make_shared.[7]

K std::integral_constant bylo doplněno přetížení operator() pro vrácení konstantní hodnoty.[16]

Pro reprezentaci celočíselných posloupností při překladu byla doplněna šablona třídy std::integer_sequence a příslušné aliasy např. pro indexy prvků v parametru pack.[20]

Globální funkce std::begin/std::end byly doplněny o funkce std::cbegin/std::cend, které vracejí konstantní iterátory, a std::rbegin/std::rend a std::crbegin/std::crend který vracet inverzní iterátory.

Šablona funkce std::exchange přiřazuje proměnné novou hodnotu a vrací její původní hodnotu.[21]

Nová přetížení std::equal, std::mismatch a std::is_permutation bere dvojici iterátorů pro druhý rozsah, tak, že volající nepotřebuje odděleně kontrolovat, že oba rozsahy mají stejnou délku.[22]

Typový rys std::is_final detekuje, že třída je final.

Manipulátor vstupně-výstupního proudu std::quoted umožňuje vkládání a extrakci řetězců obsahujících mezery umísťováním oddělovačů (implicitně uvozovek) na výstupu a jejich odstraňováním na vstupu, a escapováním všech vestavěných oddělovačů.[23]

Podpora překladačů

[editovat | editovat zdroj]

Clang dokončil podporu pro C++14 ve verzi 3.4 i když pod jménem C++1y, a od Clang 6 je chování podle C++14 implicitní.[24] GCC dokončil podporu pro C++14 v GCC 5, a od GCC 6 je chování podle C++14 implicitní.[25] Microsoft Vizuální Studio implementovalo „téměř všechny“ vlastnosti C++14 ve verzi 2017.[26]

V tomto článku byl použit překlad textu z článku C++14 na anglické Wikipedii.

  1. SUTTER, Herb. We have C++14!. [s.l.]: [s.n.], 2014-08-18. Dostupné online. 
  2. ISO/IEC 14882:2014 [online]. ISO. Dostupné online. 
  3. a b c d e WONG, Michael. The View from the C++ Standard meeting April 2013 Part 1 [online]. 2013-04-30 [cit. 2016-01-27]. Dostupné online. 
  4. a b c MERRILL, Jason. N3638 Return type deduction for normal functions (Revision 5) [online]. 2013-04-17 [cit. 2013-06-14]. Dostupné online. 
  5. Page 10 of: C++ auto and decltype Explained [online]. Dostupné online. 
  6. SMITH, Richard. N3652 Relaxing constraints on constexpr functions [online]. 2013-04-18. Dostupné online. 
  7. a b c d SUTTER, Herb. Trip Report: ISO C++ Spring 2013 Meeting [online]. isocpp.org, 2013-04-20 [cit. 2013-06-14]. Dostupné online. 
  8. DOS REIS, Gabriel. N3651 Variable Templates (Revision 1) [online]. 2013-04-19. Dostupné online. 
  9. VANDEVOORDE, Daveed; VOUTILAINEN, Ville. N3653 Member initializers and aggregates [online]. 2013-04-17. Dostupné online. 
  10. 23479 – Implement binary constants with a "0b" prefix [online]. Dostupné online. 
  11. CROWL, Lawrence; SMITH, Richard; SNYDER, Jeff; VANDEVOORDE, Daveed. N3781 Single-Quotation-Mark as a Digit Separator [online]. 2013-09-25. Dostupné online. 
  12. VALI, Faisal; SUTTER, Herb; ABRAHAMS, Dave. N3649 Generic (Polymorphic) Lambda Expressions (Revision 3) [online]. 2013-04-19. Dostupné online. 
  13. Move capture in Lambda [online]. Zásobník Přetečení. Dostupné online. 
  14. WONG, Michael. The View from the C++ Standard meeting April 2013 Part 3 [online]. 2013-04-30 [cit. 2013-06-14]. Dostupné online. 
  15. HINNANT, Howard; VOLLMANN, Detlef; BOEHM, Hans. N3659 Shared locking in C++ (Revision 2) [online]. 2013-04-19. Dostupné online. 
  16. a b c d WONG, Michael. The View from the C++ Standard meeting April 2013 Part 2 [online]. 2013-04-26 [cit. 2013-06-14]. Dostupné online. 
  17. N3657 Adding heterogeneous comparison lookup to associative containers (rev 4) [online]. 2013-03-19. Dostupné online. 
  18. SOMMERLAD, Peter. N3642 User-defined Literals for Standard Library Types (part 1 - version 4) [online]. 2013-04-18. Dostupné online. 
  19. SPERTUS, Mike. N3670 Wording for Addressing Tuples by Type: Revision 2 [online]. 2013-04-19. Dostupné online. 
  20. WAKELY, Jonathan. N3658 Compile-time integer sequences [online]. 2013-04-18 [cit. 2016-01-05]. Dostupné online. 
  21. YASSKIN, Jeffrey. N3668 exchange() utility function, revision 3 [online]. 2013-04-19 [cit. 2016-01-05]. Dostupné online. 
  22. SPERTUS, Mike; PALL, Attila. N3671 Making non-modifying sequence operations more robust: Revision 2 [online]. 2013-04-19 [cit. 2016-01-05]. Dostupné online. 
  23. DAWES, Beman. N3654 Quoted Strings Library Proposal (Revision 2) [online]. 2013-04-19 [cit. 2016-01-05]. Dostupné online. 
  24. C++ Support in Clang [online]. [cit. 2016-05-28]. Dostupné online. 
  25. C++ Standards Support in GCC [online]. [cit. 2016-05-28]. Dostupné online. 
  26. C++ Standards Conformance from Microsoft [online]. 2017-03-07 [cit. 2017-03-07]. Dostupné online. 

Externí odkazy

[editovat | editovat zdroj]