剖析C++中的常量表达式与省略号的相关作用

 更新时间:2020年4月25日 17:36  点击:2197

C++ 常量表达式
常量值是指不会更改的值。C + + 提供了两个关键字,它们使你能够表达不打算修改对象的意图,还可让你实现该意图。
C++ 需要常量表达式(计算结果为常量的表达式)以便声明:

  • 数组边界
  • case 语句中的选择器
  • 位域长度规范
  • 枚举初始值设定项

常量表达式中合法的唯一操作数是:

  • 文本
  • 枚举常量
  • 声明为使用常量表达式初始化的常量的值
  • sizeof 表达式

必须将非整型常量(显式或隐式)转换为常量表达式中合法的整型。因此,以下代码是合法的:

const double Size = 11.0;
char chArray[(int)Size];

到整型的显式转换在常量表达式中是合法的;所有其他类型和派生类型是非法的(在用作 sizeof 运算符的操作数时除外)。
逗号运算符和赋值运算符不能用于常量表达式。

省略号和可变参数模板
省略号在 C 和 C++ 中具有许多用途。这些包括函数的变量参数列表。C 运行库的 printf() 函数是一种最常见的示例。
variadic 模板是支持任意数量的参数的类或函数模板。此机制对 C++ 库开发人员尤其有用,因为您可以将其应用于类模板和函数模板,从而提供一系列类型安全和重要功能以及灵活性。
语法
可变参数模板用两种方法使用省略号。参数名称的左侧表示参数包,参数名称的右侧将参数包扩展为单独的名称。
以下是可变参数模板类定义语法的基本示例:

template<typename... Arguments> class classname;

如以下示例所示,对于参数装箱和展开,可以根据您的喜好在省略号周围添加空白,例如:

template<typename ...Arguments> class classname;

或为:

template<typename ... Arguments> class classname;

请注意本文使用的是显示在第一个例子中约定(该省略号附加于typename).
在前面的示例中,Arguments 是参数包。类 classname 可以接受参数数目可变,例如以下示例:

template<typename... Arguments> class vtclass;

vtclass< > vtinstance1;
vtclass<int> vtinstance2;
vtclass<float, bool> vtinstance3;
vtclass<long, std::vector<int>, std::string> vtinstance4;

通过使用可变参数模板类定义,您还可以要求至少一个参数。

template <typename First, typename... Rest> class classname; 

以下是可变参数模板函数语法的基本示例:

template <typename... Arguments> returntype functionname(Arguments... args);

如下一节“了解可变参数模板”所示,Arguments 参数包展开使用。
variadic 模板函数语法还可能有其他形式,包括不限制于:

template <typename... Arguments> returntype functionname(Arguments&... args); 
template <typename... Arguments> returntype functionname(Arguments&&... args);
template <typename... Arguments> returntype functionname(Arguments*... args);

还允许使用类似 const 的说明符:

template <typename... Arguments> returntype functionname(const Arguments&... args); 

按照可变参数模板类的定义,您可以创建需要至少一个参数的函数:

复制代码 代码如下:

template <typename First, typename... Rest> returntype functionname(const First& first, const Rest&... args);

可变模板使用 sizeof...() 运算符(与更早的 sizeof() 运算符不相关):

template<typename... Arguments>
void tfunc(const Arguments&... args)
{
  const unsigned numargs = sizeof...(Arguments);

  X xobj[numargs]; // array of some previously defined type X

  helper_func(xobj, args...);
}

更多有关省略号位置
过去,本文介绍了定义参数装箱和展开“在参数名称左侧的省略号位置,它表示参数,包,并在参数名称右侧,其展开参数装箱到单独的名称”。这是技术上为 true,但可能会费一番功夫在转换代码。请考虑:
模板参数列表(template <parameter-list>), typename... 介绍了模板参数包。
在参数声明语句(func(parameter-list)),“顶层”省略号介绍函数参数包,并且该省略号地位是很重要的

// v1 is NOT a function parameter pack:
template <typename... Types> void func1(std::vector<Types...> v1); 

// v2 IS a function parameter pack:
template <typename... Types> void func2(std::vector<Types>... v2); 

如果省略号在参数名之后出现,则具有参数 pack 展开。
一种阐明 variadic 模板功能框架的好方法是在 printf 一些功能的重新写入中使用:

#include <iostream>

using namespace std;

void print() {
  cout << endl;
}

template <typename T> void print(const T& t) {
  cout << t << endl;
}

template <typename First, typename... Rest> void print(const First& first, const Rest&... rest) {
  cout << first << ", ";
  print(rest...); // recursive call using pack expansion syntax
}

int main()
{
  print(); // calls first overload, outputting only a newline
  print(1); // calls second overload

  // these call the third overload, the variadic template, 
  // which uses recursion as needed.
  print(10, 20);
  print(100, 200, 300);
  print("first", 2, "third", 3.14159);
}

Output

1
10, 20
100, 200, 300
first, 2, third, 3.14159

注意
合并变参数模板函数的大多数实现使用某种形式的递归,但是它与传统递归稍有不同。传统递归涉及使用与函数相同的签名调用函数。(可以重载或模板化,但每次都要选择相同的签名。)可变递归使用不同(几乎总是减少)数目的参数调用可变函数模板,因此每次都抹去不同的签名。仍需要“基用例”,但是,递归性质是不同的。

[!--infotagslink--]

相关文章

  • C++ STL标准库std::vector的使用详解

    vector是表示可以改变大小的数组的序列容器,本文主要介绍了C++STL标准库std::vector的使用详解,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...2022-03-06
  • C++中取余运算的实现

    这篇文章主要介绍了C++中取余运算的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2021-02-23
  • 详解C++ string常用截取字符串方法

    这篇文章主要介绍了C++ string常用截取字符串方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2020-04-25
  • C++调用C#的DLL程序实现方法

    本文通过例子,讲述了C++调用C#的DLL程序的方法,作出了以下总结,下面就让我们一起来学习吧。...2020-06-25
  • C++中四种加密算法之AES源代码

    本篇文章主要介绍了C++中四种加密算法之AES源代码,小编觉得挺不错的,现在分享给大家,也给大家做个参考。...2020-04-25
  • PHP正则表达式取双引号内的内容

    取双引号内的内容我们如果一个字符串中只有一个可以使用explode来获得,但如果有多个需要使用正则表达式来提取了,具体的例子如下。 写程序的时候总结一点经验,如何只...2016-11-25
  • C++ 整数拆分方法详解

    整数拆分,指把一个整数分解成若干个整数的和。本文重点给大家介绍C++ 整数拆分方法详解,非常不错,感兴趣的朋友一起学习吧...2020-04-25
  • C++中 Sort函数详细解析

    这篇文章主要介绍了C++中Sort函数详细解析,sort函数是algorithm库下的一个函数,sort函数是不稳定的,即大小相同的元素在排序后相对顺序可能发生改变...2022-08-18
  • C++万能库头文件在vs中的安装步骤(图文)

    这篇文章主要介绍了C++万能库头文件在vs中的安装步骤(图文),文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2021-02-23
  • PHP正则表达式之捕获组与非捕获组

    今天遇到一个正则匹配的问题,忽然翻到有捕获组的概念,手册上也是一略而过,百度时无意翻到C#和Java中有对正则捕获组的特殊用法,搜索关键词有PHP时竟然没有相关内容,自己试了一下,发现在PHP中也是可行的,于是总结一下,分享的同...2015-11-08
  • php 验证只能输入汉字、英语、数字的正则表达式

    正则表达式是一门非常有用的并且进行模糊判断的一个功能了,我们下面来看通过正则来验证输入汉字、英语、数字,具体如下。 收藏了正则表达式。可以验证只能输入数...2016-11-25
  • java正则表达式判断前端参数修改表中另一个字段的值

    这篇文章主要介绍了java正则表达式判断前端参数修改表中另一个字段的值,需要的朋友可以参考下...2021-05-07
  • 详解C++ bitset用法

    这篇文章主要介绍了C++ bitset用法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2020-04-25
  • 浅谈C++中的string 类型占几个字节

    本篇文章小编并不是为大家讲解string类型的用法,而是讲解我个人比较好奇的问题,就是string 类型占几个字节...2020-04-25
  • 常用的日期时间正则表达式

    常用的日期时间正则表达式 下面收藏了大量的日期时间正则匹配函数,包括分钟,时间与秒都能达到。 正则表达式 (?n:^(?=d)((?<day>31(?!(.0?[2469]|11))|30(?!.0?2)|29(...2016-11-25
  • C++ Eigen库计算矩阵特征值及特征向量

    这篇文章主要为大家详细介绍了C++ Eigen库计算矩阵特征值及特征向量,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...2020-04-25
  • PHP正则表达式匹配验证提取网址URL实例总结

    网址规则是可寻的,所以我们可以使用正则表达式来提取字符串中的url地址了,下面一起来看看小编整理的几个PHP正则表达式匹配验证提取网址URL实例. 匹配网址 URL 的...2016-11-25
  • C++ pair的用法实例详解

    这篇文章主要介绍了C++ pair的用法实例详解的相关资料,需要的朋友可以参考下...2020-04-25
  • VSCode C++多文件编译的简单使用方法

    这篇文章主要介绍了VSCode C++多文件编译的简单使用方法,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下...2021-03-29
  • C++中的循环引用

    虽然C++11引入了智能指针的,但是开发人员在与内存的斗争问题上并没有解放,如果我门实用不当仍然有内存泄漏问题,其中智能指针的循环引用缺陷是最大的问题。下面通过实例代码给大家介绍c++中的循环引用,一起看看吧...2020-04-25