C++ 允许非类型模板参数为整数或枚举类型(整数包括布尔值和字符),以及指向任意类型的指针和引用。
我见过广泛使用的整数、布尔值和枚举参数,我很欣赏它们的实用性。我什至看到了在编译时解析字符串时巧妙地使用字符参数。
但我想知道作为指针或对任意类型的引用的非类型模板参数有哪些用例?
使用指向成员函数的指针作为模板参数使编译器可以内联对该函数的调用。在我对这个问题的回答中可以看到这种用法的一个例子:How to allow templated functor work on both member and non-member functions
在此示例中,模板参数中的指向成员函数的指针允许生成包含对指向成员函数的调用(内联)的“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 );