C ++参数包扩展

时间:2018-06-11 18:08:59

标签: c++ templates

下面的代码无法编译(请参阅代码下方的错误)。你能解释一下原因吗?

template <class F, class... Arg>
void for_each_argument(F f, Arg&&... arg)
{
   f(std::forward<Arg>(arg...));
}
int main()
{
   for_each_argument(
     [](const auto& a){std::cout<< a;}, "Aa", 3, 4);
   return 0;
}

以下是错误消息:

  

7:4:错误:表达式包含未展开的参数包   '精氨酸'

     

F(标准::向前(ARG ...));

2 个答案:

答案 0 :(得分:3)

您的代码中有几个问题。首先,你原来的行

f(std::forward<Arg>(arg...));

根本没有正确的语法 - 如果没有在模板中正确展开arg,您正在展开Arg。现在,您至少可以通过

解决这个问题
f(std::forward<Arg>(arg)...);

这样会更好,但仍然是错误的 - 你会用3个参数调用你的lambda一次,而它只接受一个 - 相反,你想用一个参数调用lambda 3次。

有几种方法可以做到这一点。首先,并且最不优选的是递归地调用该函数,如其他答案所示。这会提示丑陋的语法,并且还会增加编译器对递归模板实例化的负担。更好的解决方案是使用数组技巧扩展参数,例如(为简单起见,忽略前向):

auto lam = [&f](const auto& a) { f(a); return true;}
bool arr[] = { lam(std::forward<ARG>(arg))... };
(void)arr;

在C ++ 17中,您可以使用fold表达式来实现更加简洁的语法:

(f(std::forward<ARG>(arg)), ...);

答案 1 :(得分:2)

扩展参数包适用于需要以逗号分隔的列表的上下文。

即你的代码:

f(std::forward<Arg>(arg...));

它试图扩展到:

f( "Aa", 3, 4 );

你提供的lambda不支持这样的电话。

要将参数包扩展为多个函数调用,请使用递归函数。

template <class F>
void for_each_argument(F f)
{
    // (No args)
}

template <class F, class FirstArg, class... MoreArgs>
void for_each_argument(F f, FirstArg&& first_arg, MoreArgs&&... more_args)
{
    f( std::forward<FirstArg>(first_arg) );
    for_each_argument( f, std::forward<MoreArgs>(more_args)... );
}