Koncepty jsou rozšířením rysů šablon v programovacím jazyce C++. Jsou to pojmenované logické predikáty, které se aplikují na parametry šablon a vyhodnocují se v době překladu. Koncept může být přiřazen libovolné šabloně (šabloně třídy, šabloně funkce, členské funkci šablony třídy, šabloně proměnná nebo šablonové aliasy), a slouží jako omezení (anglicky constraint) upřesňující množinu argumentů, které mohou být použity jako parametry šablony.

Návrh konceptů se objevil již v pracovní verzi C++11; původní specifikace konceptu byla několikrát přepracována, než se formálně stala povinnou součástí C++20.

Hlavní použití

editovat

Koncepty slouží především pro:

  • zavedení typové kontroly při programování šablon
  • zjednodušení chybových hlášení překladače při selhání instanciace šablony
  • výběr přetížení šablony funkce nebo specializace šablony třídy podle vlastností typů
  • definici omezení při automatickém vyvozování typů

Typy omezení a jejich použití

editovat

Existuje pět míst v deklaraci šablony funkce, kde je možné použít omezení (níže označených jako C1 až C5):[1]

template<C1 T>
requires C2<t>
C3 auto Fun(C4 auto param) requires C5<T>;
  • C1: Typové omezení. Nahrazuje class nebo typename v deklaraci typového parametru šablony. Použití konceptu místo class nebo typename je omezení.
  • C2: Klauzule requires. Pokud nelze použít typové omezení, například protože koncept má více než jeden parametr, lze použít requires pro zadání komplikovanějších omezení.
  • C3 / C4: Omezený zástupný typ. Stejná syntaxe je dostupná pro proměnné se zástupným typem auto. Od verze C++20 jsou možné i zkrácené šablony funkcí, který používají auto jako zástupný typ v deklaraci parametrů.[2] Omezený zástupný typ umožňuje zadat omezení kladená na automaticky odvozený typ návratové hodnoty funkce nebo proměnné.
  • C5: Koncová klauzule requires. Podobá se C2 s jednou významnou výjimkou: koncovou klauzuli lze aplikovat na funkce v šabloně třídy. Díky tomu může být funkce nešablonová, což lze povolit nebo zakázat podle koncová klauzule funkce.

Omezení C1 a C2 je možné použít ve všech druzích šablon.

Příklad: equality_comparable

editovat

Následující příklad ukazuje deklaraci konceptu „equality_comparable“ z hlavičkového souboru <concepts> standardní knihovny C++20. Tomuto konceptu vyhovuje libovolný typ T takový, že pro lhodnoty a a b typu T lze přeložit výrazy a==b a a!=b i b==a a b!=a, a jejich výsledky lze zkonvertovat na typ, který vyhovuje konceptu „boolean-testable“:

// Následující koncept je implementační detail použitý pro vytvoření equality_comparable
template<typenameT, typename U>
concept weakly_equality_comparable_with = requires(const remove_reference<t>& a, const remove_reference<u>& b) {
    { a == b } -> std::same_as<bool>;
    { a != b } -> std::same_as<bool>;
    { b == a } -> std::same_as<bool>;
    { b != a } -> std::same_as<bool>;
};

template<classT>
concept equality_comparable = weakly_equality_comparable_with<t, T>;

Šablona funkce omezené tímto konceptem může být deklarována takto:

void f(const equality_comparable auto&); // omezená zkrácená deklarace šablony funkce používající omezený zástupný typ (případ C4)

nebo

template <equality_comparableT>
void f(const T&); // deklarace šablony funkce s omezením typu (C1 z předchozí ukázky)

A může být zavolána jako obvykle:

f(42); // OK, int splňuje equality_comparable

Diagnostika překladače

editovat

Pokud se programátor pokusí použít argument šablony, který nevyhovuje požadavkům této šablony, překladač vygeneruje chybu. Bez použití konceptů překladač produkuje těžko srozumitelná chybová hlášení, protože chyba není oznámena v kontextu volání, ale v interní, často hluboce vnořené, implementaci kontextu, ve kterém byl typ použit.

Například std::sort vyžaduje, aby jeho první dva argumenty byly iterátory s náhodným přístupem. Pokud argument není iterátor nebo je to iterátor jiné kategorie, dojde k chybě, když se std::sort pokusí použít jeho parametry jako obousměrné iterátory:

// std::list je obvykle obousměrný spojový seznam, jehož iterátory neumožňují libovolný přístup
std::list<int> l = {2, 1, 3};
std::sort(l.begin(), l.end());

Typická diagnostika překladače bez konceptů vyprodukuje 50 řádků chybových hlášení začínajících selháním při překladu výrazu, který se pokusí na odečtou dva iterátory:

In instantiation of 'void std::__sort(_RandomAccessIterator, _RandomAccessIterator, _Compare) [with _RandomAccessIterator = std::_List_iterator<int>; _Compare = __gnu_cxx::__ops::_Iter_less_iter]':
 error: no match for 'operator-' (operand types are 'std::_List_iterator<int>' and 'std::_List_iterator<int>')
 std::__lg(__last - __first) * 2,

[..]

S použitím konceptů lze chybu detekovat a oznámit v kontext of volání:

error: cannot call function 'void std::sort(_RAIter, _RAIter) [with _RAIter = std::_List_iterator<int>]'
note:   concept 'RandomAccessIterator()' was not satisfied

Vyhodnocování přetížení

editovat

Koncepty mohou posloužit pro výběr z přetížených šablon funkcí a specializací šablon tříd založený na/vycházela z vlastností argumentů jejich šablon, jako alternativa k přístupu „Selhání při nahrazování není chybou“ (SFINAE) a tag dispatching. Pokud argument vyhovuje více než jednomu konceptu, byl vybráno přetížení s nejvíce omezeným konceptem.

Vyvozování typu

editovat

Koncepty mohou být používán místo neomezeného vyvozování zástupného typu auto v deklaraci proměnných a typu návratové hodnoty funkce:

auto     x1 = f(y); // typ proměnné x1 je vyvozen z návratové hodnoty funkce f
Sortable auto x2 = f(y); // typ proměnné x2 je vyvozen, ale pokud nesplňuje Sortable, způsobí chybu překladu

Stav implementace

editovat

Koncepty TS definované v ISO/IEC TS 19217:2015 jsou implementovány jako experimentální rys v GCC 6.[3] C++20 koncepty jsou plně implementované v GCC 10,[4] MSVC 19.30,[5] a Clang 10.[6]

Historie

editovat

Součástí pracovního dokumentu C++11 byla odlišná verze konceptů, známá jako „C++0x Concepts“, která však byla odstraněna v roce 2009.[7] Spolu s vlastními koncepty obsahovala concept maps, rys, který by například umožnil, pro koncept „Stack“ přijmout std::vector, přičemž by automaticky namapoval operace se zásobníkem, např. push(), na odlišně pojmenované operace na typu std::vector, např. push_back()). Dále tato verze obsahovala axioms (prostředky pro zadání sémantických vlastností např. asociativity nebo komutativity, umožňující, aby překladač využíval výhody těchto vlastností bez důkazu).

Pro odlišení od tohoto opuštěného návrhu jsou koncepty zavedené v C++20 někdy označovány za „Concepts Lite“.[8]

Během schůze výboru pro normu C++ v březnu 2016, pracovní skupina pro vývoj navrhla začlenit koncepty do hlavní normy C++17, ale tento návrh byl výborem zamítnut.[9]

První verze konceptů byla začleněna do pracovní verze C++20,[10] stejně jako „The One Range“ verze rozsahů, která závisí na konceptech.

Poznámky

editovat
  1. FERTIG, Andreas, 2021. Programming with C++20. [s.l.]: Fertig Publications. Dostupné online. ISBN 978-3-949323-01-0. S. 23. 
  2. ISO/IEC 14882:2020 [online]. ISO, prosinec 2020 [cit. 2022-07-14]. Dostupné online. 
  3. GCC 6 Release Series - Changes, New Features, and Fixes [online]. Dostupné online. 
  4. C++ compiler support (gcc) [online]. Dostupné online. 
  5. C++ compiler support [online]. Dostupné online. 
  6. C++ Support in Clang [online]. Dostupné online. 
  7. Bjarne Stroustrup. The C++0x "Remove Concepts" Decision [online]. Dr. Dobbs, 2009-07-22. Dostupné online. 
  8. Andrew Sutton. Concepts Lite: Constraining Templates with Predicates [online]. isocpp.org, 2013-02-24. Dostupné online. 
  9. HONERMANN, Tom. Why Concepts didn't make C++17 [online]. honermann.net, 2016-03-06 [cit. 2016-04-19]. Dostupné v archivu pořízeném dne 2018-10-02. 
  10. 2017 Toronto ISO C++ Committee Discussion Thread (Concepts in C++20; Coroutines, Ranges and Networking TSes published) : cpp [online]. 2017-07-15. Dostupné online. 

Reference

editovat

V tomto článku byl použit překlad textu z článku Concepts (C++) na anglické Wikipedii.* SUTTON, Andrew; STROUSTRUP, Bjarne, 2011. Design of Concept Libraries for C++. In: International Conference on Software Language Engineering. [s.l.]: [s.n.]. Dostupné online.

Související články

editovat

Externí odkazy

editovat