Templates and generic programming
T.65
Используйте диспетчеризацию по тегам для предоставления альтернативных реализаций функций
Причина
- Шаблон определяет общий интерфейс.
- Диспетчеризация по тегам позволяет выбирать реализации на основе конкретных свойств типа аргумента.
- Производительность.
Пример
Это упрощённая версия std::copy (без учёта возможности несмежных последовательностей)
struct trivially_copyable_tag {};
struct non_trivially_copyable_tag {};
// T не является тривиально копируемым
template<class T> struct copy_trait { using tag = non_trivially_copyable_tag; };
// int является тривиально копируемым
template<> struct copy_trait<int> { using tag = trivially_copyable_tag; };
template<class Iter>
Out copy_helper(Iter first, Iter last, Iter out, trivially_copyable_tag)
{
// использовать memmove
}
template<class Iter>
Out copy_helper(Iter first, Iter last, Iter out, non_trivially_copyable_tag)
{
// использовать цикл с вызовом конструкторов копирования
}
template<class Iter>
Out copy(Iter first, Iter last, Iter out)
{
using tag_type = typename copy_trait<std::iter_value_t<Iter>>::tag;
return copy_helper(first, last, out, tag_type{})
}
void use(vector<int>& vi, vector<int>& vi2, vector<string>& vs, vector<string>& vs2)
{
copy(vi.begin(), vi.end(), vi2.begin()); // использует memmove
copy(vs.begin(), vs.end(), vs2.begin()); // использует цикл с конструкторами копирования
}
Это общая и мощная техника выбора алгоритма во время компиляции.
Примечание
С ограничениями C++20 такие альтернативы можно различать напрямую:
template<class Iter>
requires std::is_trivially_copyable_v<std::iter_value_t<Iter>>
Out copy_helper(In, first, In last, Out out)
{
// использовать memmove
}
template<class Iter>
Out copy_helper(In, first, In last, Out out)
{
// использовать цикл с конструкторами копирования
}
Контроль
???