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.

Другие вопросы по тегам