Концепція (C++)
Концепція (англ. concept) — це доповнення до шаблонів наявних у мові програмування C++. Концепції це іменовані логічні предикати на параметри шаблонів обчислювані під час компіляції. Концепцію можна прив'язати до шаблона (шаблона класу, шаблона функції або функції члена шаблона класу), у такому випадку вона слугує обмеженням: яке встановлює множину агрументів прийнятних як параметри шаблона.
Перед тим як увійти до C++20 пропоновану ще для C++11 початкову специфікацію концепцій було переглянуто багато разів.
Основні застосування
Основні застосування концепцій такі:
- Упровадження перевіряння типів для шаблонного програмування
- Спрощення діагностування компілятором невдалих інстанціювань шаблонів
- Вибирання перевантажень шаблонів функцій і спеціалізацій шаблоних класів виходячи з властивостей типу
- Обмеження автоматичного виведення типів
Діагностика компілятора
Якщо програміст спробує використати аргумент, що не відповідає вимогам шаблону, компілятор згенерує помилку. Без використання концепцій такі помилки часто важко зрозумілі, бо помилки стосуються не самого виклику, а гніздяться глибше по ланцюжку викликів в тому місці де цей тип використовують.
Наприклад, std::sort
вимагає, щоб два його перші аргументи були ітераторами довільного доступу. Якщо аргумент не ітератор або ж ітератор іншої категорій, то компілятор згенерує помилку коли std::sort
спробує використати цей параметр як двоспрямований ітератор:
std::list<int> l = {2, 1, 3};
std::sort(l.begin(), l.end());
Типова діагностика без коцепцій містить більш ніж 50 рядків коду і починається з повідомлення про невдачу компіляції виразу, що намагається відняти два ітератори:
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
,
Із використання концепцій, помилку можна виявити і повернути таку діагностику в контексті виклику:
error: cannot call function 'void std::sort(_RAIter, _RAIter) [with _RAIter = std::_List_iterator<int>]'
note: concept 'RandomAccessIterator()' was not satisfied
Виведення типів
Концепції можна використати замість необмеженого заповнювача виведення типів auto
оголошуючи змінні:
auto x1 = f(y); // компілятор виводить тип x1 відповідно до того, що повертає f
Sortable auto x2 = f(y); // компілятор виводить тип x2, але успішно компілює лише якщо він задовольняє Sortable