“……”令牌是啥意思?即参数包上的双省略号运算符

Posted

技术标签:

【中文标题】“……”令牌是啥意思?即参数包上的双省略号运算符【英文标题】:What is the meaning of "... ..." token? i.e. double ellipsis operator on parameter pack“……”令牌是什么意思?即参数包上的双省略号运算符 【发布时间】:2011-08-03 07:02:48 【问题描述】:

在浏览 gcc 当前实现的新 C++11 标头时,我偶然发现了“......”标记。您可以检查以下代码 compiles fine [via godbolt.org]。

template <typename T>
struct X
 /* ... */ ;

template <typename T, typename ... U>
struct X<T(U......)> // this line is the important one
 /* ... */ ;

那么,这个token是什么意思呢?

编辑:看起来问题标题中的“......”被修剪为“......”,我的意思是“......”。 :)

【问题讨论】:

提示:它是...,后跟... 是不是更像 U... 后跟 ... 。尽管如此,还是很奇怪。 注意:这可以在&lt;functional&gt;&lt;type_traits&gt; 中找到,总是在模板参数内的函数参数列表的上下文中。 我发现让它卡在标题中的唯一方法是在两者之间放置一个空格......希望它能让读者更清楚。 @Matthieu M.:谢谢,好多了! 【参考方案1】:

这种奇怪的每个实例都与一个常规的单个省略号的情况配对。

  template<typename _Res, typename... _ArgTypes>
    struct _Weak_result_type_impl<_Res(_ArgTypes...)>
     typedef _Res result_type; ;

  template<typename _Res, typename... _ArgTypes>
    struct _Weak_result_type_impl<_Res(_ArgTypes......)>
     typedef _Res result_type; ;

  template<typename _Res, typename... _ArgTypes>
    struct _Weak_result_type_impl<_Res(_ArgTypes...) const>
     typedef _Res result_type; ;

  template<typename _Res, typename... _ArgTypes>
    struct _Weak_result_type_impl<_Res(_ArgTypes......) const>
     typedef _Res result_type; ;

我的猜测是双省略号在含义上与 _ArgTypes..., ... 相似,即可变参数模板扩展后跟 C 样式的可变参数列表。

Here's a test 支持该理论……我认为我们有一个新的赢家,因为我们是有史以来最差的伪操作员。

编辑:这似乎是一致的。 §8.3.5/3 描述了一种将参数列表形成为的方法

参数声明列表opt ...opt

所以双省略号是由一个以参数包结尾的参数声明列表组成,后跟另一个省略号。

逗号完全是可选的; §8.3.5/4 确实说

在语法正确且“...”不是抽象声明符的一部分的情况下,“, ...”与“...”同义。

这个在一个抽象声明器中,[edit],但是 Johannes 提出了一个很好的观点,他们指的是参数声明中的一个抽象声明器。我想知道他们为什么不说“参数声明的一部分”,以及为什么这句话不仅仅是一个信息性注释……

此外,&lt;cstdarg&gt; 中的va_begin() 需要在可变参数列表之前有一个参数,因此C++ 专门允许的原型f(...) 是没有用的。与 C99 交叉引用,在普通 C 中是非法的。所以,这是最奇怪的。

使用说明

根据要求,双省略号here is a demonstration:

#include <cstdio>
#include <string>

template< typename T >
T const &printf_helper( T const &x )
     return x; 

char const *printf_helper( std::string const &x )
     return x.c_str(); 

template< typename ... Req, typename ... Given >
int wrap_printf( int (*fn)( Req... ... ), Given ... args ) 
    return fn( printf_helper( args ) ... );


int main() 
    wrap_printf( &std::printf, "Hello %s\n", std::string( "world!" ) );
    wrap_printf( &std::fprintf, stderr, std::string( "Error %d" ), 5 );

【讨论】:

是的,没错。 T(U..., ...) 但是也可以很好地编译;也许他们想节省一些空间。 :) 但这意味着什么?以及编译器如何知道 _ArgTypes 在哪里结束以及一些“额外”参数从哪里开始? @Bo Persson: std::is_functionvalue 必须为真,即使该函数是 C 可变参数之一并且因为 T(U...) 是 匹配对于这样的功能,你需要这种疯狂。例如。 int f(int, char, ...) 与 T(U......) 完全匹配 T = int, U = int, char 和“...”可变参数标记。 “这个 is 在一个抽象声明器中”-> 它们的意思是不是同一参数类型列表的最后一个参数的抽象声明器的一部分。例如void (int...)... 不是抽象声明符int 的一部分,因此它是void(int, ...) 的同义词。如果你写void(T...) 并且T 是一个模板参数包,... 将是抽象声明符的一部分,因此它不等同于void(T, ...) "此外, 中的 va_begin() 需要在 varargs 列表之前有一个参数,因此 C++ 明确允许的原型 f(...) 是没有用的。" -- 如果你想知道传递了哪些参数,它只是没用的。 f(...) 被大量用作模板元编程中的后备函数重载,其中不需要此信息(甚至实际上没有调用该函数)。【参考方案2】:

在vs2015上,模板版本中逗号分隔是必不可少的:

    template <typename T, typename ... U>
    struct X<T(U...,...)> ;// this line is the important one

一个实例化的例子是:

    X<int(int...)> my_va_func;

问候, 调频。

【讨论】:

我也注意到了这一点,它仍然会发生。错误报告developercommunity.visualstudio.com/content/problem/437260/…。 很高兴知道。对此有任何参考或引用标准吗? .سلام بخشید نمیدانم 这是一个公共论坛。让人们阅读你的想法。 PLZ 为私人消息保留原生语言。 سپاس. 好的。我不是该标准的专家 - 我认为其他人已经在上面详细介绍了它。如果有人愿意对 Microsoft 问题报告发表评论,那么它可能会提高其优先级。该报告显示 clang 和 gcc 允许 VC++ 不允许的内容,因此我认为我们可能处于相当强大的基础上。

以上是关于“……”令牌是啥意思?即参数包上的双省略号运算符的主要内容,如果未能解决你的问题,请参考以下文章

servlet 映射 url 模式上的双通配符 (*) 是啥意思?

Java的方法参数中的双感叹号和#号是啥意思?

(function($)...)(jQuery)是啥意思

请问股票当中的MID是啥意思?

令牌是啥?令牌简介

Pig中的双冒号到底是啥意思?