std::get не пересылает ссылку на rvalue для std::apply
Мне интересно почему std::apply
не пересылает rvalue-reference
при работе со ссылочными типами в кортежах (см. Live):
#include <type_traits>
#include <tuple>
template<typename T>
void assertRvalueReference(T&& t)
{
static_assert(std::is_rvalue_reference_v<decltype(t)>, "Ups");
}
int main()
{
struct A{};
A a;
int v;
auto t = std::tuple<A&&, int>(std::move(a), v); // essentially `std::forward_as_tuple(v, std::move(a))`
std::apply([](auto&& arg, ...)
{
assertRvalueReference(std::forward<decltype(arg)>(arg));
}, std::move(t));
std::apply([](auto&& arg, ...)
{
// assertRvalueReference(arg); // This should in my opinion not fail
}, t);
assertRvalueReference(non_std_get<0>(t));
}
Основная причина этого std::get
и правило сворачивания ссылок. Разве не было бы больше смысла, если быstd::apply
внутренне будет использовать это non_std_get
template<std::size_t Index, typename Tuple>
constexpr decltype(auto) non_std_get(Tuple&& t)
{
using Type = std::tuple_element_t<Index, std::remove_cvref_t<Tuple>>;
if constexpr(std::is_rvalue_reference_v<Type>)
{
return std::move(std::get<Index>(t));
}
else
{
return std::get<Index>(t);
}
}
что привело бы к идеальному форварду для
std::apply([](auto&& arg){/*arg is here `int&&`*/}, t);
1 ответ
Проблема не в std::apply
, это в вашей лямбде.
Внутри вашей лямбды arg
это всегда именующий. Вам нужно явно привести его к rvalue с помощьюstd::forward
чтобы сделать его rvalue.