从std :: get完美转发元组值

时间:2018-01-31 00:04:22

标签: c++ tuples forward perfect-forwarding

我有一个类似于std::apply的很好的实现,它将一个元组扩展为一个函数的参数。它完美地工作,除了std::get总是返回一个左值并且它无法匹配正确的重载。

POC代码可在此处找到:https://wandbox.org/permlink/OUYMQY2afL8vRMUu

我们的想法是将std::forward添加到apply_sequence,以便打印ONE TWO THREE

void printNumber(const int& x, const int& y)
{
    std::cout << "ONE" << std::endl;
}

void printNumber(const int& x, int&& y)
{
    std::cout << "TWO" << std::endl;
}

void printNumber(int&& x, const int& y)
{
    std::cout << "THREE" << std::endl;
}

template<typename... TTuple, std::size_t... Indices>
auto apply_sequence(const std::tuple<TTuple...>& tuple, std::index_sequence<Indices...>)
{
    // missing: forward value to proper type (currently is always lvalue)
    return printNumber(std::get<Indices>(tuple)...);
}

template<typename... TTuple>
auto apply_tuple(const std::tuple<TTuple...>& tuple)
{
    return apply_sequence(tuple, std::index_sequence_for<TTuple...>());
}

int main(int argc, char* argv[])
{
    std::tuple<int, int> one { 1, 2 };
    apply_tuple(one); // ONE

    std::tuple<int, int&&> two { 1, 2 };
    apply_tuple(two); // TWO

    std::tuple<int&&, int> three { 1, 2 };
    apply_tuple(three); // THREE

    return 0;
}

编辑:如果有人想要问题的解决方案https://wandbox.org/permlink/XkUjfypAMepJRPgZ

1 个答案:

答案 0 :(得分:1)

原因是如果tuple参数是左值,std::get返回左值,即使该元素是右值引用。您可以编写自己的my_get来解决它:

// If the element is not an rvalue reference, behave the same as std::get
template< std::size_t I, class... Types >
constexpr std::enable_if_t <
              !std::is_rvalue_reference_v<std::tuple_element_t<I, std::tuple<Types...>>>, 
               std::tuple_element_t<I, std::tuple<Types...>>const&
          >
    my_get( const std::tuple<Types...>& t ) noexcept
{
    return std::get<I>(t);
}

// If the element is an rvalue reference, move the result of std::get
template< std::size_t I, class... Types >
constexpr std::enable_if_t <
              std::is_rvalue_reference_v<std::tuple_element_t<I, std::tuple<Types...>>>, 
              std::tuple_element_t<I, std::tuple<Types...>>
          >
    my_get( const std::tuple<Types...>& t ) noexcept
{
    return std::move(std::get<I>(t));
}

在代码中使用my_get代替std::get,然后一切顺利。