【问题标题】:Can variadic expansions be used as a chain of comma-operator calls?可变参数扩展可以用作逗号运算符调用链吗?
【发布时间】:2012-04-19 10:21:57
【问题描述】:

我在看“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”括在括号中,和/或使用后增量;均未奏效。)

【问题讨论】:

  • 你用可变参数模板参数定义了operator+吗?
  • 查找关于可变参数模板的维基百科文章。前段时间,我在文章中添加了一些关于此类扩展的技术。

标签: c++ c++11 comma variadic


【解决方案1】:

仅在某些情况下才允许拆包,逗号分隔的语句不属于它们。用你的话:扩展是语义上的而不是词汇上的。但是,这并不重要,因为还有其他几种方法可以做到这一点。已经有某种模式/习惯用法来编写简单的可变参数函数。一种方法:

使用辅助模板函数,它什么都不做:

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)...);

【讨论】:

  • 这个答案是错误的(即使用起来很危险)。参数评估的顺序未定义,因此副作用的顺序也未定义。它应该是一个template&lt;class T&gt; void pass(T) 函数,以initializer_list 作为其参数:pass({(something)...})stackoverflow.com/questions/621542/…
  • @polkovnikov.ph:嗯,我不会说它。它与每个带有副作用的函数调用一样正确或错误。但你是对的。有定义评估顺序的替代方案。但是,我会建议对具有可变参数构造函数的类进行 大括号初始化,而不是 std::initializer_list
  • 啊,但是如果你想做args.foo()...foo 返回void呢?
猜你喜欢
  • 2019-10-10
  • 2020-04-22
  • 2011-01-24
  • 1970-01-01
  • 2015-01-23
  • 2021-06-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多