通过元组完美转发参数

Gum*_*mgo 5 c++ tuples variadic-templates perfect-forwarding forwarding-reference

我有一个理想情况下应如下所示的函数:

\n
template<typename... t_buffers, t_function function>\nvoid iterate_buffers(t_buffers &&... buffers, t_function &&function);\n
Run Code Online (Sandbox Code Playgroud)\n

但是,除非参数包类型位于最后,否则无法推断出参数包类型,因此我的函数签名如下:

\n
template<typename... t_buffers_and_function>\nvoid iterate_bufferes(t_buffers_and_function &&... buffers_and_function);\n
Run Code Online (Sandbox Code Playgroud)\n

然后参数会被重新排列,以便函数排在第一位。为了执行此改组,我使用了此处描述的技术,但在尝试转发元组时遇到了问题。

\n

这是一个存在问题的简化示例:

\n
template<typename... t_args>\nvoid inner(std::tuple<t_args &&...> args) {};\n\ntemplate<typename... t_args>\nvoid outer(t_args &&... args) {\n    inner(std::forward_as_tuple(std::forward<t_args>(args)...));\n}\n
Run Code Online (Sandbox Code Playgroud)\n

如果我传递右值(例如通过调用outer(1, 2);),它会按预期工作。但是,如果我传递左值 ( int x = 1; int y = 2; outer(x, y);),则会出现以下语法错误:

\n
error: could not convert \xe2\x80\x98std::forward_as_tuple(_Elements&& ...) [with _Elements = {int&, int&}]((* & std::forward<int&>((* & args#1))))\xe2\x80\x99 from \xe2\x80\x98std::tuple<int&, int&>\xe2\x80\x99 to \xe2\x80\x98std::tuple<int&&, int&&>\xe2\x80\x99\ninner(std::forward_as_tuple(std::forward<t_args>(args)...));\n~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n
Run Code Online (Sandbox Code Playgroud)\n

因此forward_as_tuple已按预期生成了左值引用的元组std::tuple<int&, int&>,因为提供的值outer是左值。不应该inner接受右值或左值的元组,因为std::tuple<t_args &&...> args正在使用转发引用?为什么它抱怨无法转换为右值?在该上下文中是否不允许转发引用(因为 args 不简单T &&),因此args被迫仅是右值的元组?(我在网上找到的例子似乎使用了std::tuple<t_args &&...>语法。)

\n

inner如果我从:中删除转发引用的使用,该错误就会消失void inner(std::tuple<t_args...> args)。那么 的类型argsstd::tuple<int&, int&>如果我将左值传递给outer,并且std::tuple<int&&, int&&>如果我传递右值。也许这里不需要转发引用,因为正确的左值/右值类型已经编码到元组中并且不需要转发?我很困惑,因为我在网上看到的所有示例(包括我链接的示例)都使用具有inner转发引用的原始调用签名。

\n