While working on a project I encounter a situation std::apply does not forward rvalue references from std::tuple created by std::forward_as_tuple *IF* resulting std::tuple is stored in a variable! However if std::forward_as_tuple result is not stored in a variable, but is just passed as a second argument to std::apply then it works and rvalue reference gets perfectly forwarded.
I tried many options including using different types for std::tuple, like
decltype(auto) t = forward_as_tuple(1, std::move(r))
auto t = forward_as_tuple(1, std::move(r))
auto&& t = forward_as_tuple(1, std::move(r))
auto& t = forward_as_tuple(1, std::move(r))
Nothing helped to store a tuple in a variable and then pass it to std::apply. It appears like lvalue reference being forwarded at the end to std::__invoke by std::apply...
There is a godbolt link to my code: https://godbolt.org/z/24LYP5
Code snippet
#include <functional>
#include <iostream>
auto product(int l, int&& r) { return l * r; }
static void test_not_works()
{
int r = 2;
decltype(auto) t = std::forward_as_tuple(1, std::move(r));
std::apply(product, t);
}
static void test_works()
{
int r = 2;
std::apply(product, std::forward_as_tuple(1, std::move(r)));
}
Error message
In file included from /opt/compiler-explorer/gcc-7.3.0/include/c++/7.3.0/functional:54:0,
from <source>:1:
/opt/compiler-explorer/gcc-7.3.0/include/c++/7.3.0/tuple: In instantiation of 'constexpr decltype(auto) std::__apply_impl(_Fn&&, _Tuple&&, std::index_sequence<_Idx ...>) [with _Fn = int (&)(int, int&&); _Tuple = std::tuple<int&&, int&&>&; long unsigned int ..._Idx = {0, 1}; std::index_sequence<_Idx ...> = std::integer_sequence<long unsigned int, 0, 1>]':
/opt/compiler-explorer/gcc-7.3.0/include/c++/7.3.0/tuple:1671:31: required from 'constexpr decltype(auto) std::apply(_Fn&&, _Tuple&&) [with _Fn = int (&)(int, int&&); _Tuple = std::tuple<int&&, int&&>&]'
<source>:10:26: required from here
/opt/compiler-explorer/gcc-7.3.0/include/c++/7.3.0/tuple:1662:27: error: no matching function for call to '__invoke(int (&)(int, int&&), int&, int&)'
return std::__invoke(std::forward<_Fn>(__f),
~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~
std::get<_Idx>(std::forward<_Tuple>(__t))...);
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
In file included from /opt/compiler-explorer/gcc-7.3.0/include/c++/7.3.0/tuple:41:0,
from /opt/compiler-explorer/gcc-7.3.0/include/c++/7.3.0/functional:54,
from <source>:1:
/opt/compiler-explorer/gcc-7.3.0/include/c++/7.3.0/bits/invoke.h:89:5: note: candidate: template<class _Callable, class ... _Args> constexpr typename std::__invoke_result<_Functor, _ArgTypes>::type std::__invoke(_Callable&&, _Args&& ...)
__invoke(_Callable&& __fn, _Args&&... __args)
^~~~~~~~
/opt/compiler-explorer/gcc-7.3.0/include/c++/7.3.0/bits/invoke.h:89:5: note: template argument deduction/substitution failed:
/opt/compiler-explorer/gcc-7.3.0/include/c++/7.3.0/bits/invoke.h: In substitution of 'template<class _Callable, class ... _Args> constexpr typename std::__invoke_result<_Functor, _ArgTypes>::type std::__invoke(_Callable&&, _Args&& ...) [with _Callable = int (&)(int, int&&); _Args = {int&, int&}]':
/opt/compiler-explorer/gcc-7.3.0/include/c++/7.3.0/tuple:1662:27: required from 'constexpr decltype(auto) std::__apply_impl(_Fn&&, _Tuple&&, std::index_sequence<_Idx ...>) [with _Fn = int (&)(int, int&&); _Tuple = std::tuple<int&&, int&&>&; long unsigned int ..._Idx = {0, 1}; std::index_sequence<_Idx ...> = std::integer_sequence<long unsigned int, 0, 1>]'
/opt/compiler-explorer/gcc-7.3.0/include/c++/7.3.0/tuple:1671:31: required from 'constexpr decltype(auto) std::apply(_Fn&&, _Tuple&&) [with _Fn = int (&)(int, int&&); _Tuple = std::tuple<int&&, int&&>&]'
<source>:10:26: required from here
/opt/compiler-explorer/gcc-7.3.0/include/c++/7.3.0/bits/invoke.h:89:5: error: no type named 'type' in 'struct std::__invoke_result<int (&)(int, int&&), int&, int&>'
Compiler returned: 1