C ++在带有右值缓冲区的ostream中使用snprintf,这是格式正确的吗?
Posted
技术标签:
【中文标题】C ++在带有右值缓冲区的ostream中使用snprintf,这是格式正确的吗?【英文标题】:C++ using snprintf in ostream with rvalue buffer, is this well-formed? 【发布时间】:2014-12-01 21:13:07 【问题描述】:我想知道是否可以在ostream
中使用snprintf
格式,这样我就可以在流表达式本身中嵌入对snprintf
的调用。这在 GCC 4.9 中编译,但是可以吗?
cout << [](char (&&buf) [12], int d) snprintf(buf, 12, "%d", d); return buf; ( , 15) << endl;
【问题讨论】:
那行代码必须为 lambda 的使用赢得一些奖项。 IMO 真正的问题是
如何绑定到数组类型的右值,以及这意味着什么。当我们回答这个问题时,关于这段代码是否定义了行为的问题将得到回答。此外,您在该行末尾附近还有一个额外的)
。
@cdhowie,关于问题的性质,我认为您是正确的。我删除了多余的)
【参考方案1】:
这是格式良好且定义明确的。 用于复制列表初始化对
char [12]
的右值引用,这会创建一个临时的char [12]
数组,引用绑定到该数组。这个临时存在直到完整表达式的结尾——在这种情况下,直到分号,所以指向数组中元素的指针可以安全地返回并用于在该表达式中打印。 (lambda 返回一个 char *
指向该数组的第一个元素。)
标准:
§8.5 [dcl.init]/p17:
初始化器的语义如下。 [...]
如果初始化程序是(非括号)braced-init-list,则对象或引用是列表初始化的 (8.5.4)。
§8.5.4 [dcl.init.list]/p3:
定义了
[...] 否则,如果T
类型的对象或引用的列表初始化 如下:T
是引用类型,则T
引用的类型的prvalue 临时被复制列表初始化或 直接列表初始化,取决于初始化的类型 引用,并且引用绑定到该临时文件。 [注意: 像往常一样,如果 引用类型是对非常量类型的左值引用。 —结束说明 ]
§12.2 [class.temporary]/p5:
在函数调用中临时绑定到引用参数 (5.2.2) 一直持续到包含 打电话。
【讨论】:
【参考方案2】:我很确定这没问题。如果我理解正确,lambda 将返回一个 char[12]
类型的对象作为临时对象(来自自动返回类型推导)。然后可以将该临时值传递给另一个函数,在本例中为 operator<<()
。
这确实意味着制作了副本,但 RVO 可能会处理这个问题。
更新
如 cmets 和 T.C. 提供的更好答案中所述,此 lambda 推导的返回类型实际上是 char* 而不是 char[12]。我已经用 GCC 中的代码确认了这一点。
【讨论】:
它不返回char [12]
。它返回一个char *
。以上是关于C ++在带有右值缓冲区的ostream中使用snprintf,这是格式正确的吗?的主要内容,如果未能解决你的问题,请参考以下文章