C ++ допускает, чтобы параметры шаблона не типового типа имели целочисленный или перечислимый тип (с целочисленным, включая логическое и символьное), а также указатели и ссылки на произвольные типы.
Я видел широко используемые целочисленные, логические и перечислимые параметры, и я ценю их полезность. Я даже видел умное использование параметров символов для разбор строк во время компиляции.
Но мне интересно, каковы некоторые варианты использования для не типовых параметров шаблона, которые являются указателями или ссылками на произвольные типы?
Использование указателя на член-функцию в качестве параметра шаблона позволяет компилятору встроить вызов этой функции. Пример такого использования можно увидеть в моем ответе на этот вопрос: Как разрешить шаблонному функтору работать с функциями-членами и не-членами
В этом примере функция указателя на член в параметре шаблона позволяет генерировать функцию «thunk», которая содержит вызов (встроенный) функции указателя на член. Указатель на функцию thunk имеет общую подпись (и фиксированный размер), что позволяет хранить и копировать ее с минимальными затратами времени выполнения, в отличие от функции указателя на член.
если вы знаете адрес буфера во время компиляции, вы можете принять решение (во время компиляции) на основе его выравнивания, особенно для таких вещей, как memcpy, это позволяет вам пропустить любую проверку во время выполнения и просто перейти прямо к копирование данных с использованием наиболее эффективных размеров.
(Я предполагаю) Вы также можете скомпилировать-утверждать, что переданный указатель выровнен по странице (полезно, например, для протокола nvme), хотя я не знаю, как это выглядит.
Я думаю, что важно, указатель-шаблон-аргумент Операции.
(Где более косвенный путь — указатель на функцию, а более простой — объект-функция [который, в свою очередь, снова является типом.])
template<typename Key, class Val, bool (*CMP)(Key const&, Key const&)>
class map
{
};
template<typename KEY, class VALUE, typename CMP = std::less<KEY>>
class map
{
public:
CMP cmp;
};
Поскольку вы не знаете, какое сравнение применять заранее, вы не можете встроить его в контейнер. Он должен быть предоставлен либо внешне для любой функции, которая требует его, либо через шаблон.
Ранее я использовал односвязный список (указатели данных, хранящиеся в элементах данных), который был параметризован указателем на элемент данных, указывающим, где в списке хранятся его ссылки. Эта параметризация позволяет хранить один и тот же элемент данных в нескольких списках, если они используют разные члены ссылки:
template <class T, T* (T::*Link)> class ilist;
struct Node {
Node* a_next;
Node* b_next;
};
typedef ilist<Node, &Node::a_next> a_list;
typedef ilist<Node, &Node::b_next> b_list;
Вот полезный пример нецелых параметров шаблона. Несколько предварительных объявлений (не все, но достаточно, чтобы понять):
template <bool flag, class T, class F> struct SelectType
{
typedef T Result;
};
template <class T, class F> struct SelectType<false, T, F>
{
typedef F Result;
};
#define PARAMETER( selector, type ) typename SelectType<TypeTraits<T>::selector, type,
#define PTR_TRAITS typename ::Linderdaum::Utils::TypeTraits<T>::PointeeType
#define REF_TRAITS typename ::Linderdaum::Utils::TypeTraits<T>::ReferredType
using namespace ::Linderdaum::Utils;
template <class T> struct ParameterType
{
typedef
PARAMETER( IsString, clStringParameter )
PARAMETER( IsReference, clPODParameter<REF_TRAITS> )
PARAMETER( IsPointer, clPointerParameter<PTR_TRAITS> )
PARAMETER( IsFundamental, clPODParameter<T> )
// default
clPODParameter<T>
>::Result
>::Result
>::Result
>::Result
Type;
};
И фактический код использования:
clParametersList Params;
ParameterType<const LString& >::Type Param0;
ParameterType<size_t >::Type Param1;
ParameterType<clDownloadCompleteCallback >::Type Param2;
Param0.ReadValue( &P0 );
Param1.ReadValue( &P1 );
Param2.ReadValue( &P2 );
Params.push_back( &Param0 );
Params.push_back( &Param1 );
Params.push_back( &Param2 );