据我所知,当包含参数包的模式右侧出现省略号(...)时,模式会对包中的每个参数展开一次.然而,尽管我已经能够通过扩展找到模式的孤立示例,但我无法找到模式构成的定义.从我所看到的,空格在模式的定义中没有任何作用,但是括号有.例如,在此示例中:
template<typename ... Ts>
void func(Ts)
{
do_something(validate(Ts)...);
}
Run Code Online (Sandbox Code Playgroud)
该do_something行将扩展为:
do_something(validate(var1), validate(var2), validate(var3))
Run Code Online (Sandbox Code Playgroud)
如果Ts碰巧代表三个变量.相比之下:
do_something(validate(Ts...));
Run Code Online (Sandbox Code Playgroud)
将扩大到:
do_something(validate(var1, var2, var3));
Run Code Online (Sandbox Code Playgroud)
因此,明确括号与确定模式的开始和结束位置有关.我也可以看到空白没有.但这只能让我到目前为止.我想知道什么构成一个模式,以及它将如何扩展.我尝试搜索C++标准,但发现太多"参数包"实例使其有效.有人可以给我一个"模式"的定义,或定义的链接,或两者兼而有之?
更新:为了限制我的问题的范围,我想集中讨论在函数调用中出现模式的情况.我已经相应地编辑了标题.对不起,我从一开始就没说清楚.
甲图案在根据标准中所定义[temp.variadic/4:(经由@tc)
甲包扩展由一个的图案和省略号,实例化,其中产生所述图案的零个或多个实例中的列表(下面描述).模式的形式取决于扩展发生的环境.包扩展可以在以下上下文中发生:
- 在函数参数包([ dcl.fct ])中; 模式是没有省略号的参数声明.
- 在作为包扩展的模板参数包([ temp.param ])中:
- 如果模板参数包是参数声明 ; 模式是没有省略号的参数声明 ;
- 如果模板参数包是带有template-parameter-list的type-parameter ; 模式是没有省略号的相应类型参数.
- 在初始化列表中([ dcl.init ]); 该模式是初始化子句.
- 在base-specifier-list(Clause [ class.derived ]中;模式是base-specifier.
- 在mem-initializer-list([ class.base.init ])中,mem-initializer的mem-initializer-id表示基类; 模式是mem-initializer.
- 在template-argument-list([ temp.arg ])中; 模式是模板参数.
- 在动态异常规范([ except.spec ])中; 模式是type-id.
- 在属性列表中([ dcl.attr.grammar ]); 模式是一个属性.
- 在alignment-specifier([ dcl.align ])中; 模式是没有省略号的alignment-specifier.
- 在捕获列表中([ expr.prim.lambda ]); 模式是捕获.
- 在
sizeof...表达式([ expr.sizeof ]); 模式是一个标识符.- 在fold-expression([ expr.prim.fold ])中; 模式是包含未扩展参数包的强制转换表达式.
标准草案的上述引用说明了链接中描述的语法的哪个部分是正在扩展的"模式".要理解它,您需要知道如何描述C++语法以及有关如何在标准文本本身中使用它的例外情况; 但是,如果你有基本的BNF知识和一点耐心,你可以解决它.这些名字通常也很有用.
但是,你可以使用...并且大部分都能理解它而不会那么深.
在一般的规则很简单:你有C++的语法(称为的一些位模式以通常的方式,其中一个类型的包像一个单一的类型处理解析),和文字的包像一个单一的文字处理.然后,在它结束时,你有一个...扩展器.然后它将所有未扩展的包装在C++语法的位之前(模式)并扩展它.
它在每种情况下的工作原理是不同的 ; 它不仅仅是一次宏观扩张....上面列举了有效的上下文; 扩展的影响在标准中列出了有效的每个点.
在最普通的用例中...,模式是一个表达式,并且表达式被扩展为 - 如果每个副本由,(不是operator,,但是另一个"正常")分隔,通常在一个事物列表的上下文中预期的(函数调用,初始化列表等).
有一些函数参数声明上下文(...两者都扩展了函数参数的类型,并引入了一个参数名称的新包),在模板参数列表中(通常引入包),等等.
sizeof...有点奇怪:因为sizeof...它计算了传递的包中有多少元素().这的工作方式不同,因为...它不适用于"左边的结构".
因为alignas(X...),我们最终得到alignas(X@0), alignas(X@1), ...(@0我的伪代码是包的第一个元素),因为alignas(X@0, X@1, ...)它不是有效的C++(在下面的评论中再次是@TC).
对于继承,它创建一组基类.对于mem-initializer-lists,它允许您将ctor参数传递给所述基类包.对于lambdas,它为您提供有限的包捕获(在我检查的最后扩展表达式上没有完整).
模式是扩展的东西.重要的是,扩展模式不会被另一个模式扩展器扩展:所以std::array< Ts, sizeof...(Ts) >...是一组各种类型的数组,每个数组都有许多元素,这些元素由包本身的大小决定. sizeof...(Ts)"算作扩展" Ts在其中(),即使...不是"它的权利",因为语言定义Ts了()作为扩展的模式....
一般情况下的模式不能称为表达式,因为类型不是表达式,而某些模式是表达式(或至少扩展为表达式列表).在某些情况下,...将类型模式扩展为扩展的类型包(如throw表达式中).
一般规则,你认为...在本地上下文中以适当的方式扩展左边的东西,除了sizeof...(这是一个神奇的操作符告诉你参数包中有多少元素)之外几乎可以工作.只是在角落的情况下,这不会产生一个像样的模型.根据我的经验,更糟糕的是它会导致代码在您认为应该编译时无法编译; 在这种情况下,您可以学习解决方法.就像,记住一个简单的声明"没有本地上下文",所以你做不到a = std::get<Is>(tup))...;,而是解决方法(void)(int[]){0,(a = std::get<Is>(tup)),0)...};(可能必须键入dede int[]),我们提供一个上下文(创建一个数组)供包扩展工作.
C++ 1z的折叠表达式是另一个古怪的地方,...不适用于左边; 在这里,他们希望扩展一个二元运算符,所以"在左边"并没有像通常的"一元"扩展那样有意义.
| 归档时间: |
|
| 查看次数: |
699 次 |
| 最近记录: |