C++详解非类型模板参数Nontype与Template及Parameters的使用

 更新时间:2022年06月24日 09:03:58   作者:loongknown  
除了类型可以作为模板参数,普通值也可以作为模板函数,即非类型模板参数(Nontype Template Parameters)。下面让我们一起了解一下

非类型类模板参数

前一章使用的例子 Stack 使用的是标准库中的容器管理元素,也可以使用固定大小的 std::array,它的优势是内存管理开销更小,数组的大小可以交给用户指定。

#include <array>
#include <cassert>
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) // start with no elements
{
  // 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; // append element
  ++numElems; // increment number of elements
}
template<typename T, std::size_t Maxsize>
void Stack<T,Maxsize>::pop ()
{
  assert(!elems.empty());
  --numElems; // decrement number of elements
}
template<typename T, std::size_t Maxsize>
T const& Stack<T,Maxsize>::top () const
{
  assert(!elems.empty());
  return elems[numElems-1]; // return last element
}
int main()
{
  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
  // manipulate stack of up to 20 ints
  int20Stack.push(7);
  std::cout << int20Stack.top() << '\n';
  int20Stack.pop();
  // manipulate stack of up to 40 strings
  stringStack.push("hello");
  std::cout << stringStack.top() << '\n';
  stringStack.pop();
}

使用该模板需要同时指定类型和个数。 Maxsize 用于指定 std::array 的大小。非类型模板参数也可以有默认值。

template<typename T = int, std::size_t Maxsize = 100>
class Stack {
  ...
};

非类型函数模板参数

也可以为函数定义非类型模板参数。

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

也可以指定一个模板参数,由该参数之前的参数推断出其类型。

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

或者保证传值的类型和指定的类型相同。

template<typename T, T Val = T{}>
T bar();

非类型模板参数的限制

需要注意的是,非类型模板参数有一定的限制。一般地,非类型模板参数可以是整形(包括枚举)、指向对象/函数/成员的指针、对象/函数的左值引用或空指针类型 std::nullptr_t

浮点数和类类型对象不可以作为非类型模板参数。

template<double VAT>        // ERROR: floating-point values are not
double process (double v)   // allowed as template parameters
{
  return v * VAT;
}
template<std::string name>  // ERROR: class-type objects are not
class MyClass {             // allowed as template parameters
  ...
};

当使用指针或引用作为非类型模板参数时,不能用字符串字面值、临时对象、数据成员或其他子对象作模板实参。

template<char const* name>
class MyClass {
  ...
};
MyClass<"hello"> x; // ERROR: string literal "hello" not allowed

C++版本逐渐放宽了限制。C+11 之前,对象必须有外部链接;C++17 之前对象必须有外部或内部链接;C++17 放开了此限制。

extern char const s03[] = "hi"; // external linkage
char const s11[] = "hi"; // internal linkage
int main()
{
  MyClass<s03> m03; // OK (all versions)
  MyClass<s11> m11; // OK since C++11
  static char const s17[] = "hi"; // no linkage
  MyClass<s17> m17; // OK since C++17
}

非类型模板参数的实参可能是任何编译期表达式。

template<int I, bool B>
class C;
...
C<sizeof(int) + 4, sizeof(int)==4> c;

当表达式中使用了大于号,需要将整个表达式用小括号括起来。

C<42, sizeof(int) > 4> c; // ERROR: first > ends the template argument list
C<42, (sizeof(int) > 4)> c; // OK

非类型模板参数 auto

从 C++17 开始, 可以将非类型模板参数定义为 auto,以接收任何允许作为非类型模板参数的类型。

#include <array>
#include <cassert>
template<typename T, auto Maxsize>
class Stack {
  public:
    using size_type = decltype(Maxsize);
  private:
    std::array<T,Maxsize> elems; // elements
    size_type 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;
	}
	size_type size() const { // return current number of elements
	  return numElems;
	}
};
// constructor
template<typename T, auto Maxsize>
Stack<T,Maxsize>::Stack ()
 : numElems(0) // start with no elements
{
  // nothing else to do
}
template<typename T, auto Maxsize>
void Stack<T,Maxsize>::push (T const& elem)
{
  assert(numElems < Maxsize);
  elems[numElems] = elem; // append element
  ++numElems; // increment number of elements
}
template<typename T, auto Maxsize>
void Stack<T,Maxsize>::pop ()
{
  assert(!elems.empty());
  --numElems; // decrement number of elements
}
template<typename T, auto Maxsize>
T const& Stack<T,Maxsize>::top () const
{
  assert(!elems.empty());
  return elems[numElems-1]; // return last element
}

从 C++14 开始,已经支持使用 auto 作为函数返回值。因此成员函数 size() 可以简写为:

auto size() const { // return current number of elements
  return numElems;
}

上述模板的使用:

int main()
{
  Stack<int,20u> int20Stack; // stack of up to 20 ints
  Stack<std::string, 40> stringStack; // stack of up to 40 strings
  // manipulate stack of up to 20 ints
  int20Stack.push(7);
  std::cout << int20Stack.top() << '\n';
  auto size1 = int20Stack.size();
  stringStack.push("hello");
  std::cout << stringStack.top() << '\n';
  auto size2 = stringStack.size();
  if (!std::is_same_v<decltype(size1), decltype(size2)>) {
    std::cout << "size types differ" << '\n';
  }
}

前面说过,非类型模板参数 auto 接收任何允许作为非类型模板参数的类型。

#include <iostream>
template<auto T> // take value of any possible nontype parameter (since C++17)
class Message {
  public:
   void print() {
     std::cout << T << '\n';
   }
};
int main()
{
  Message<42> msg1;
  msg1.print(); // initialize with int 42 and print that value:42
  static char const s[] = "hello";
  Message<s> msg2; // initialize with char const[6] "hello"
  msg2.print(); // and print that value:hello
}

非类型模板 auto 的参数仍不能是浮点数。

Stack<int,3.14> sd; // ERROR: Floating-point nontype argument

使用 decltype(auto) 指定非类型模板参数的类型也是可以的。

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

参考 http://www.tmplbook.com

到此这篇关于C++详解非类型模板参数Nontype与Template及Parameters的使用的文章就介绍到这了,更多相关C++非类型模板参数内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • C++中rapidjson组装map和数组array的代码示例

    C++中rapidjson组装map和数组array的代码示例

    今天小编就为大家分享一篇关于C++中rapidjson组装map和数组array的代码示例,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起跟随小编来看看吧
    2019-04-04
  • C语言中的for循环语句基本语法及使用

    C语言中的for循环语句基本语法及使用

    这篇文章主要介绍了C语言中的for循环语句基本语法及使用,本文结合实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2023-06-06
  • C语言的数据结构之树、森连、二叉树之间的转换图解

    C语言的数据结构之树、森连、二叉树之间的转换图解

    这篇文章主要介绍了C语言的数据结构之树、森连、二叉树之间的转换详解,数据是信息的载体,是描述客观事物属性的数、字符以及所有能输入到计算机中并被程序识别和处理的符号的集合,需要的朋友可以参考下
    2023-07-07
  • VS2022 CUDA环境配置的实现步骤

    VS2022 CUDA环境配置的实现步骤

    本文主要介绍了VS2022 CUDA环境配置的实现步骤,文中通过图文示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-05-05
  • C++简单集合类的实现方法

    C++简单集合类的实现方法

    如何使用C++实现一个简单的集合类,这篇文章主要介绍了C++简单集合类的实现方法,感兴趣的小伙伴们可以参考一下
    2016-07-07
  • 从汇编看c++中变量类型的深入分析

    从汇编看c++中变量类型的深入分析

    本篇文章是对c++中的变量类型进行了详细的分析介绍。需要的朋友参考下
    2013-05-05
  • C++ Boost Bind库示例分析使用

    C++ Boost Bind库示例分析使用

    Boost是为C++语言标准库提供扩展的一些C++程序库的总称。Boost库是一个可移植、提供源代码的C++库,作为标准库的后备,是C++标准化进程的开发引擎之一,是为C++语言标准库提供扩展的一些C++程序库的总称
    2022-11-11
  • 深入浅析STL vector用法

    深入浅析STL vector用法

    这篇文章给大家介绍 stl vector用法,主要知识点在如何恰当的使用它们的成员函数,涉及到条件函数和函数指针在迭代算法中的使用,对stl vector用法感兴趣的朋友可以参考下本文
    2015-10-10
  • C语言函数之memcpy函数用法实例

    C语言函数之memcpy函数用法实例

    memcpy函数用于把资源内存(src所指向的内存区域)拷贝到目标内存(dest所指向的内存区域),下面这篇文章主要给大家介绍了关于C语言函数之memcpy函数用法的相关资料,文中通过实例代码介绍的非常详细,需要的朋友可以参考下
    2022-08-08
  • C++实现简易的通讯录管理系统

    C++实现简易的通讯录管理系统

    这篇文章主要为大家详细介绍了C++实现简易的通讯录管理系统,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-06-06

最新评论