第3章 非类型模板参数:3.4 模板参数类型auto
3.4 Template Parameter Type auto
3.4 模板参数类型auto
Since C++17, you can define a nontype template parameter to generically accept any type that is allowed for a nontype parameter. Using this feature, we can provide an even more generic stack class with fixed size:
从C++17开始,你可以定义一个非类型模板参数,该参数可普遍接受非类型模板参数允许的任意类型。利用这个特性,我们可以提供一个具有固定大小的更通用的栈(stack)。
#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 isempty 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 }
By defining
按照定义
template<typename T, auto Maxsize> class Stack { … };
by using the placeholder type auto, you define Maxsize to be a value of a type not specified yet. It might be any type that is allowed to be a nontype template parameter type.
通过使用占位符类型auto,可以将Maxsize定义为尚未指定类型的值。它可以是非类型模板参数允许的任何类型。
Internally you can use both the value:
在模板内部,你可以这两个值
std::array<T, Maxsize> elems; //元素及其类型: using size_type = decltype(Maxsize);
which is then, for example, used as return type of the size() member function:
例如,将它作为size()成员函数的返回类型:
size_type size() const { //return current number of elements return numElems; }
Since C++14, you could also just use auto here as return type to let the compiler find out the return type:
从C++14开始,你也可以在此处使用auto作为返回类型,以便让编译器找出返回类型:
auto size() const { //return current number of elements return numElems; }
With this class declaration the type of the number of elements is defined by the type used for the number of elements, when using a stack:
通过这个类的声明,元素数量的类型(即size()的返回类型)是由使用栈时定义的元素数量的类型决定的。
#include <iostream> #include <string> #include "stackauto.hpp" 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(); // manipulate stack of up to 40 strings 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’; } }
With
通过
Stack<int,20u> int20Stack; // stack of up to 20 ints
the internal size type is unsigned int, because 20u is passed.
内部size的类型为unsigned int类型,因为传入20u。
With
通过
Stack<std::string,40> stringStack; // stack of up to 40 strings
the internal size type is int, because 40 is passed. size() for the two stacks will have different return types, so that after
内部size的类型为int型,因为传入40。两个栈的size()函数具有不同的把返回类型,因此,当定义
auto size1 = int20Stack.size(); … auto size2 = stringStack.size();
the types of size1 and size2 differ. By using the standard type trait std::is_same (see Section D.3.3 on page 726) and decltype, we can check that:
之后,size1和size2的类型是不同的。通过标准的类型萃取std::is_same(请参阅第726页的D3.3节)和decltype,我们可以检验这点:
if (!std::is_same<decltype(size1), decltype(size2)>::value) { std::cout << "size types differ" << ’\n’; }
Thus, the output will be:
因此,输出结果为:
size types differ
Since C++17, for traits returning values, you can also use the suffix _v and skip ::value (see Section 5.6 on page 83 for details):
从C++17开始,为了萃取返回值,你也可以使用后缀“_v“并省略”::value“(详细信息,请参阅第83页的5.6节)
if (!std::is_same_v<decltype(size1), decltype(size2)>) { std::cout << "size types differ" << ’\n’; }
Note that other constraints on the type of nontype template parameters remain in effect. Especially, the restrictions about possible types for nontype template arguments discussed in Section 3.3 on page 49 still apply. For example:
注意,对于非类型模板参数类型的其他约束仍然有效。特别是,第49页3.3节中讨论的关于非类型模板参数可能类型的限制仍然适用。
Stack<int, 3.14> sd; // ERROR: 浮点数不能作为非类型模板参数
And, because you can also pass strings as constant arrays (since C++17 even static locally declared; see Section 3.3 on page 49), the following is possible:
并且,因为你还可以将字符串作为常量数组进行传递(从C++17开始,甚至是局部静态声明,见第49页的3.3节),因此,可以出现以下的情况:
#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(); //用整数42初始化,并打印该值。 static char const s[] = "hello"; Message<s> msg2; // 用char const[6] "hello"初始化 msg2.print(); // 并打印该值 }
Note also that even template<decltype(auto) N> is possible, which allows instantiation of N as a reference:
还要注意,甚至template<decltype(auto> N>也是可能的,它允许将N初始化为引用。
template<decltype(auto) N> class C { … }; int i; C<(i)> x; // N为 int&(注意,是个引用类型)
See Section 15.10.1 on page 296 for details.
更多详细信息,请参阅第296页的15.10.1节。
3.5 Summary
3.5 总结
• Templates can have template parameters that are values rather than types.
模板可以具有值模板参数,而不是类型模板参数。
• You cannot use floating-point numbers or class-type objects as arguments for nontype template parameters. For pointers/references to string literals, temporaries, and subobjects, restrictions apply.
对于非类型模板参数,你不能使用浮点数、class类型的对象。对于字符串字面量、临时对象及其子对象的的指针/引用类型,有一些限制。
• Using auto enables templates to have nontype template parameters that are values of generic types.
使用auto可以使非类型模板参数具有泛型类型的值。
- 非类型模板参数知识点梳理
- C++非类型模板参数
- 模板:如何判断模板参数T为内建数据类型
- 求变量的数据类型,typeid,bool,C和C++的不同,new和delete,C++中的枚举,inline和可变参数模板,auto和函数模板,宽字符
- 非类型模板参数示例
- 从 windows 到 linux(1):g++不能用函数内定义的类型做模板参数
- C++11 图说VS2013下的引用叠加规则和模板参数类型推导规则
- 非类型模板参数
- 非类型模板参数
- 用于datagrid模板针对不同的数据类型的参数归总
- 数量不定的模板参数、auto、for的新形式、reference
- 非类型模板参数与 非类型类模板参数的使用
- 非类型函数模板参数
- 接收数组的函数模板对参数类型推断
- 模板笔记003 - 非类型模板参数
- 非类型的函数模板参数
- C++11 引用叠加规则和模板参数类型推导规则
- 模板参数类型,仿函数
- Mat类型中的CV_8UC3、CV_32FC3以及对应的迭代器模板参数Vec3b,Vec3f的一点自己的理解
- c++类模板及参数类型的运行时判断