c++11-17 模板核心知识(三)—— 非类型模板参数 Nontype Template Parameters

时间:2022-05-28 15:06:16

模板参数不一定非得是类型,它们还可以是普通的数值。我们仍然使用前面文章的Stack的例子。

类模板的非类型模板参数

声明:

template <typename T, std::size_t Maxsize>
class Stack {
private:
std::array<T, Maxsize> elems; // elements
std::size_t numElems; // current number of elements
public:
Stack(); // constructor
void push(T const &elem); // push element
void pop(); // pop element
T const &top() const; // return top element
bool empty() const { // return whether the stack is empty
return numElems == 0;
}
std::size_t size() const { // return current number of elements
return numElems;
}
};

实现:

template <typename T, std::size_t Maxsize>
Stack<T, Maxsize>::Stack() : numElems(0) {
// nothing else to do
} template <typename T, std::size_t Maxsize>
void Stack<T, Maxsize>::push(T const &elem) {
assert(numElems < Maxsize);
elems[numElems] = elem;
++numElems;
}

使用:

Stack<int,20> int20Stack;       // stack of up to 20 ints
Stack<int,40> int40Stack; // stack of up to 40 ints
Stack<std::string,40> stringStack; // stack of up to 40 strings

这个很简单,就不细说了。

函数模板的非类型模板参数

template<int Val, typename T>
T addValue (T x) {
return x + Val;
} std::transform(source.begin(), source.end(), dest.begin(), addValue<5, int>);

再比如标准库type_traits中的enable_ifconditional:

template <bool _Bp, class _If, class _Then>
struct _LIBCPP_TEMPLATE_VIS conditional {typedef _If type;}; template <bool, class _Tp = void> struct _LIBCPP_TEMPLATE_VIS enable_if {};

限制

必须是下面的类型:

  • 整型常量/枚举
  • 指向对象/函数/成员变量的指针
  • 对象/函数的左值引用
  • std::nullptr_t

当传递指针或者引用时,指向的对象不能是字符串常量、临时变量、数据成 员以及其它子对象。

使用auto推断非类型模板参数

从c++17起,可以使用auto推断非类型模板参数:

template <auto value> void f() { }

f<10>();               // deduces int

如果没有auto,想将非类型模板参数的类型也当做模板参数,那么必须声明两个模板参数:

template <typename Type, Type value> constexpr Type TConstant = value;

constexpr auto const MySuperConst = TConstant<int, 100>;

从c++17开始,只需要一个auto即可:

template <auto value> constexpr auto TConstant = value;

constexpr auto const MySuperConst = TConstant <100>;

在auto推导的的情况下获取类型:

template<auto Val, typename T = decltype(Val)>
T foo();

或者:

template<auto Val> struct Value {
using ArgType = decltype(Val);
};

template<decltype(auto) N>也是可以的,这里N会被推断成引用类型:

template<decltype(auto) N>
class C {
...
};
int i;
C<(i)> x; // N is int&

(完)

朋友们可以关注下我的公众号,获得最及时的更新:

c++11-17 模板核心知识(三)—— 非类型模板参数 Nontype Template Parameters