1

Тема: template<typename...::type * = nullptr> Як читати цей шаблон ?

Шукав бібліотеку для окремої задачі, треба було робити конволюцію матрицьою, а знайшов цікаві синтаксні конструкції :

template <typename T, typename enable_if<!has_mod<T>::value>::type * = nullptr>
T lagrange_interpolate_iota(vc<T> &f, T c) {
    // ...
}

що таке typename - знаю думав що знаю,
що таке nullptr - знаю, але не розумію чому тут не nullptr_t, ну ок, може тут треба саме значеня, але тоді куди йде присвоєня (?) ..
що таке enable_if - знаю, але бачу доведеться повторно перечитати.
Чому там * після ::type ? Це ше C++ чи .. не важливо. Важливо зрозуміти як це користувати.
Якщо серед вас є ті, хто може пояснити або дати посиланя, то кидайте, буду читати.

про has_mod

has_mod - це їх бібліотека містить там такий шаблон-клас

class has_mod : public decltype(has_mod_impl::check<T>(std::declval<T>())) {};

за такі штуки не переймайтесь, мене більше цікавлять саме C++, std, і особливо подібні template'и.

2

Re: template<typename...::type * = nullptr> Як читати цей шаблон ?

Читаємо зсередини:
has_mod<T> - шаблон has_mod для типу T
!has_mod<T>::value - інверсія значення value з цього шаблону. Щось булеве.
enable_if<!has_mod<T>::value>::type - член-тип type шаблону enable_if, який існує лише якщо параметр enable_if є true.
якийсь_тип * = nullptr - це покажчик без імені
Якщо типу enable_if<...>::type не існує, то конструкція не має сенсу і за SFINAE не інстаціюється.
Якщо цей тип існує, то створюється параметр, який неможливо використати, бо в нього немає імені, зі значенням nullptr.

Тобто це - просто SFINAE: якщо enable_if спрацює, то буде шаблон функції lagrange_interpolate_iota з одним параметром T, а якщо не спрацює, то такого шаблону функції взагалі не буде.

Подякували: leofun011

3

Re: template<typename...::type * = nullptr> Як читати цей шаблон ?

leofun01 написав:

Чому там * після ::type ? Це ше C++ чи .. не важливо. Важливо зрозуміти як це користувати.

Це спосіб досягнення SFINAE: функція може бути обрана, лише якщо всі типи можуть бути належним чином підставлені (substituted). За допомогою SFINAE ми лише намагаємося викликати цю помилку підстановки (substitution failure).

Ось цей ::type - це тип члена отриманий з enable_if після всіх перевірок. Тобто отримуємо ми щось таке:

template <typename T>
struct enable_always
{
  typedef T type; // наш `::type`
};

enable_if - це все ще хак (в C++20 ми маємо концепти якраз для цього); за замовчуванням цим type членом є просто void.

Якщо has_mod<T>::value має значення false (тобто T не є тим, що ви перевіряєте у has_mod), std::enable_if<...> не матиме типу члена, таким чином відбувається помилка підставлення (substitution failure), і ця функція не працюватиме.

Якщо T є тим, що ви перевіряєте у has_mod, тоді typename std::enable_if<has_mod<T>::value>::type буде void, тому ми додаємо * та = nullptr. Це типовий абюз безіменного параметра, зі значенням за замовчуванням як 0 (або nullptr), це необхідно, щоб приховати другий параметр шаблона.

Можна писати ще, як:

template <typename T, typename enable_if<!has_mod<T>::value, int >::type = 0>
template <typename T, typename enable_if<!has_mod<T>::value, bool>::type = true>
Подякували: koala, leofun012

4

Re: template<typename...::type * = nullptr> Як читати цей шаблон ?

Прийнято. Так файно пояснили, навіть дитина зрозуміє. Для кращого запамятовуваня ще попробую старі коди переписати.