关于折叠表达式与cout的输出顺序疑问及编译问题
理解C++折叠表达式的展开顺序与语法规则
嘿,我来帮你拆解这个问题,搞清楚为什么你的代码输出是123而不是预期的321,以及反过来写为什么编译失败。
一、为什么原代码输出123?
你写的这段代码用了C++17的折叠表达式,核心是这一行:
(std::cout << ... << std::forward<Args>(args)) << '\n';
这属于二元左折叠,语法形式是(初始化表达式 op ... op 参数包)。它的展开规则是从左到右依次将参数包中的元素与初始化表达式结合,最终展开成:
((std::cout << 1) << 2.0) << "3" << '\n';
因为std::cout的operator<<是左结合的,所以执行顺序就是先输出1,接着输出2.0(会被自动转换成2),再输出字符串"3",最终得到123。
二、为什么cout << forward(args) << ...无法编译?
折叠表达式有严格的语法要求,它必须符合以下两种形式之一:
- 一元折叠:要么是
... op 参数包(右折叠),要么是参数包 op ...(左折叠) - 二元折叠:要么是
(初始化表达式 op ... op 参数包)(左折叠),要么是(参数包 op ... op 初始化表达式)(右折叠)
你写的cout << forward(args) << ...完全不符合这些语法规则——编译器无法识别...在这里的作用,自然会抛出编译错误。
三、如果想输出321该怎么做?
直接用<<的折叠表达式做不到逆序输出,因为operator<<要求左操作数是输出流,右操作数是要输出的值,逆序的话会导致流出现在<<的右侧,不符合运算符的定义。
要实现逆序输出,你可以借助std::index_sequence来逆序访问参数包,比如用C++20的模板lambda实现:
#include <iostream> #include <utility> #include <tuple> template<typename ...Args> void print_reverse(Args&&... args) { auto tuple = std::make_tuple(std::forward<Args>(args)...); // 用模板lambda+索引序列逆序访问元组元素 [&]<std::size_t... Is>(std::index_sequence<Is...>) { (std::cout << std::get<sizeof...(Args)-1-Is>(tuple) << ...); }(std::make_index_sequence<sizeof...(Args)>{}); std::cout << '\n'; } int main() { print_reverse(1, 2.0, "3"); // 输出321 }
内容的提问来源于stack exchange,提问作者NoSenseEtAl
相关产品推荐
相关产品推荐

