在可变参数模板的上下文中,"..."标记的规则是什么?

Ral*_*zky 96 c++ variadic-templates c++11

在C++ 11中有像这样的可变参数模板:

template< class T, class... Args >
unique_ptr<T> make_unique( Args&&... args )
{
    return unique_ptr<T>(new T(std::forward<Args>(args)...));
}
Run Code Online (Sandbox Code Playgroud)

有一些好奇这个问题:表达std::forward<Args>(args)...同时使用Argsargs,但只有一个...令牌.此外,std::forward是一个非可变参数模板函数,只接受一个模板参数和一个参数.那个(大致)的语法规则是什么?如何概括?

另外:在函数实现中,省略号(...)位于感兴趣的表达式的末尾.有没有理由在模板参数列表和参数列表中省略号位于中间?

Naw*_*waz 96

在可变参数模板的上下文中,省略号...用于解析模板参数包,如果它出现在表达式的右侧(暂时调用此表达式模式).规则是重复左侧的任何模式... - 解包模式(现在称它们为表达式)用逗号分隔,.

通过一些例子可以最好地理解它.假设你有这个功能模板:

template<typename ...T>
void f(T ... args) 
{
   g( args... );        //pattern = args
   h( x(args)... );     //pattern = x(args)
   m( y(args...) );     //pattern = args (as argument to y())
   n( z<T>(args)... );  //pattern = z<T>(args)
}
Run Code Online (Sandbox Code Playgroud)

现在,如果我将此函数调用T为as {int, char, short},则每个函数调用都会扩展为:

g( arg0, arg1, arg2 );           
h( x(arg0), x(arg1), x(arg2) );
m( y(arg0, arg1, arg2) );
n( z<int>(arg0), z<char>(arg1), z<short>(arg2) );
Run Code Online (Sandbox Code Playgroud)

在您发布的代码中,std::forward遵循n()函数调用所示的第四个模式.

注意之间x(args)...和之间的区别y(args...)!


您也可以使用...初始化数组:

struct data_info
{
     boost::any  data;
     std::size_t type_size;
};

std::vector<data_info> v{{args, sizeof(T)}...}; //pattern = {args, sizeof(T)}
Run Code Online (Sandbox Code Playgroud)

这扩展到这个:

std::vector<data_info> v 
{ 
   {arg0, sizeof(int)},
   {arg1, sizeof(char)},
   {arg2, sizeof(short)}
};
Run Code Online (Sandbox Code Playgroud)

我刚刚意识到一个模式甚至可以包含访问说明符public,如下例所示:

template<typename ... Mixins>
struct mixture : public Mixins ...  //pattern = public Mixins
{
    //code
};
Run Code Online (Sandbox Code Playgroud)

在此示例中,模式扩展为:

struct mixture__instantiated : public Mixin0, public Mixin1, .. public MixinN  
Run Code Online (Sandbox Code Playgroud)

也就是说,从所有基类公开mixture派生.

希望有所帮助.

  • @synther:那里不需要`sizeof ...(T)`.你可以简单地写:`int a [] = {___};` (3认同)

typ*_*232 47

以下内容摘自Andrei Alexandrescu在GoingNative 2012上的演讲"Variadic Templates are Funadic".我可以推荐它,以便对可变参数模板进行详细介绍.


使用可变电池组可以做两件事.可以应用于sizeof...(vs)获取元素的数量并进行扩展.

扩展规则

Use            Expansion

Ts...          T1, ..., Tn
Ts&&...        T1&&, ..., Tn&&
x<Ts,Y>::z...  x<T1,Y>::z, ..., x<Tn,Y>::z
x<Ts&,Us>...   x<T1&,U1>, ..., x<Tn&,Un>
func(5,vs)...  func(5,v1), ..., func(5,vn)
Run Code Online (Sandbox Code Playgroud)

扩张向内进行.在锁定步骤中扩展两个列表时,它们必须具有相同的大小.

更多例子:

gun(A<Ts...>::hun(vs)...);
Run Code Online (Sandbox Code Playgroud)

Ts在模板参数列表中展开all ,A然后hun使用all扩展函数vs.

gun(A<Ts...>::hun(vs...));
Run Code Online (Sandbox Code Playgroud)

扩展Ts模板参数列表中的Aall和all vs作为函数参数hun.

gun(A<Ts>::hun(vs)...);
Run Code Online (Sandbox Code Playgroud)

hun使用Tsvs以锁定步骤扩展功能.

注意:

Ts不是一种类型,vs也不是一种价值!它们是类型/值列表的别名.任何一个列表都可能是空的.两者都只服从特定的行动.所以以下是不可能的:

typedef Ts MyList;  // error!
Ts var;             // error!
auto copy = vs;     // error!
Run Code Online (Sandbox Code Playgroud)

扩展基因座

函数参数

template <typename... Ts>
void fun(Ts... vs)
Run Code Online (Sandbox Code Playgroud)

初始化列表

any a[] = { vs... };
Run Code Online (Sandbox Code Playgroud)

基本说明符

template <typename... Ts>
struct C : Ts... {};
template <typename... Ts>
struct D : Box<Ts>... { /**/ };
Run Code Online (Sandbox Code Playgroud)

成员初始化列表

// Inside struct D
template <typename... Us>
D(Us... vs) : Box<Ts>(vs)... {}
Run Code Online (Sandbox Code Playgroud)

Tempate参数列表

std::map<Ts...> m;
Run Code Online (Sandbox Code Playgroud)

只有在参数可能匹配时才会编译.

捕获列表

template <class... Ts> void fun(Ts... vs) {
    auto g = [&vs...] { return gun(vs...); }
    g();
}
Run Code Online (Sandbox Code Playgroud)

属性列表

struct [[ Ts... ]] IAmFromTheFuture {};
Run Code Online (Sandbox Code Playgroud)

它在规范中,但没有可以表示为类型的属性.