来自 std::get 的完美转发元组值
perfect forwading tuple values from std::get
我有一个类似于 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
原因是如果元组参数是左值,std::get
returns 是左值,即使元素是右值引用。你可以自己写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
,那么一切顺利。
我有一个类似于 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
原因是如果元组参数是左值,std::get
returns 是左值,即使元素是右值引用。你可以自己写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
,那么一切顺利。