#c++ #шаблоны_с++ #c++14
Изучая новый стандарт C++, натолкнулся на нововведение «шаблоны переменных» Синтаксис у шаблона следующий: template < typename T > constexpr T value = T(1234); О применении шаблона написано: Данная возможность позволяет создавать и использовать constexpr шаблоны переменных, для более удобного сочетания с шаблонными алгоритмами. Не вполне понимаю, как такая переменная будет использоваться в шаблонном алгоритме. Не могли бы Вы привести несколько примеров использования этого механизма? Также не понимаю, почему нельзя такое шаблонное constexpr выражение заменить нешаблонным, ведь значение мы указываем явно, соответственно, и тип можем написать (вывести) явно.
Ответы
Ответ 1
В стандарте есть пример: templateconstexpr T pi = T(3.1415926535897932385L); template T circular_area(T r) { return pi * r * r; } Здесь шаблон переменной позволяет получить константу нужного размера - float/double/etc. Другое популярное применение - это замена is_some ::value на is_some_v , например template< class T, class U > inline constexpr bool is_same_v = is_same ::value; // C++17 Ответ 2
Тут можно заметить, что при объявлении шаблона переменной тип этой переменной совсем не обязан совпадать с параметром шаблона или вообще быть как-то связан с параметром(-ами) шаблона. Большинство тривиальных примеров шаблонов переменных обычно дают переменной тот же самый тип, что использовался в параметре шаблона, что может создать ложное впечатление, как будто это требуется. На самом деле шаблонная переменная может иметь любой тип. Например, пользуясь примером с площадью окружности, вы можете принять решение использовать "базовое" определение константы PI с конкретным типом double templateconstexpr double PI = 3.141592653589793; а затем, пользуясь явной специализацией, добавить специализированные определения для отдельных плавающих типов template<> constexpr float PI = 3.1415927; template<> constexpr long double PI = 3.141592653589793238L; После этого можно будет реализовать "единую" шаблонную функцию вычисления площади окружности template T circle_area(T r) { return PI * r * r; } которая будет, например, работать и с целочисленными типами int area = circle_area(10); Для целочисленных типов в качестве константы PI будет браться вариант "по умолчанию" с типом double, а для плавающих типов будут использоваться специализированные значения этой константы. Вариант реализации этой функции из ответа @Abyx, как вы наверное заметили, тоже будет "работать" с целочисленными типами. Но в том варианте константа Пи для целочисленных типов получит целочисленное значение 3, что не всегда желательно. Также можно добавить, что возможность включения статических членов-данных в шаблоны классов существовала в языке С++ с самого начала стандартизованных времен, т.е. в С++98. Это позволяло реализовывать "шаблоны переменных" уже тогда, пользуясь фактически той же самой техникой, которая в С++98 применялась для "шаблонных typedef", т.е. через помещение типов или переменных в "обертку" шаблонного класса. В частности, вышеприведенный пример может быть реализован на классическом С++98 как template struct PI { static const double value; }; template const double PI ::value = 3.141592653589793; template <> struct PI { static const float value; }; const float PI ::value = 3.1415927; template <> struct PI { static const long double value; }; const long double PI ::value = 3.141592653589793238L; template T circle_area(T r) { return PI ::value * r * r; } Принимая это во внимание, можно сказать, что шаблонные переменные не являются каким-то фундаментально новым свойством С++14. Они (выражаясь нестрого) являются просто "синтаксическим сахаром", более компактным и элегантным вариантом синтаксиса для записи вышеприведенного С++98 варианта реализации. Ситуация аналогична введенной в С++11 возможность объявления шаблонных typedef (через using), которая тоже может быть названа "синтаксическим сахаром" над хорошо известной С++98 техникой "шаблонного typedef".
Комментариев нет:
Отправить комментарий