c++ 变元展开式可以用作逗号运算符调用链吗?

plupiseo  于 2023-01-15  发布在  其他
关注(0)|答案(2)|浏览(91)

我正在查看“How to properly use references with variadic templates”,想知道逗号扩展能走多远。
以下是答案的变体:

inline void inc() { }

template<typename T,typename ...Args>
inline void inc(T& t, Args& ...args) { ++t; inc(args...); }

由于可变参数被扩展为一个 * 逗号 * 分隔的元素列表,这些逗号在语义上等同于模板/函数参数分隔符吗?或者它们是在词法上插入的,使它们适合于任何(后预处理器)使用,包括逗号运算符?
这在我的GCC-4.6上工作:

// Use the same zero-argument "inc"

template<typename T,typename ...Args>
inline void inc(T& t, Args& ...args) { ++t, inc(args...); }

但当我试着:

// Use the same zero-argument "inc"

template<typename T,typename ...Args>
inline void inc(T& t, Args& ...args) { ++t, ++args...; }

我不断收到解析错误,期待“;“,并且“args”不会扩展它的包。为什么它不起作用?是因为如果“args”为空,我们会得到一个无效的标点符号块吗?是法律的的,还是我的编译器不够好?
(我试过将“args”放在圆括号中,和/或使用后置增量;两者都不起作用。)

zqry0prt

zqry0prt1#

只有在特定的上下文中才允许解包,逗号分隔的语句不属于这些上下文。扩展是语义上的,而不是词汇上的。但是,这并不重要,因为还有其他几种方法可以实现它。已经有一些模式/习惯用法可以编写简单的变元函数。实现它的一种方法是:
使用一个helper模板函数,它什么也不做:

template <typename ...Args>
void pass(Args&&...) { }

将表达式传递给此函数,而不是使用逗号运算符:

template <typename ...Args>
void inc(Args&&... args)
{
    pass(++std::forward<Args>(args)...);
}

如果表达式必须更复杂,你可以在扩展中使用逗号操作符。如果一些operator++有返回类型void,这可能会很有用:

pass((++std::forward<Args>(args), 0)...);
eni9jsuy

eni9jsuy2#

C++17增加了fold expression

template<typename ...Args>
inline void inc(Args& ...args) { (++args, ...); }

相关问题