我想实现一个通用的
tuple_map
接受函子和
std::tuple
,将函子应用于此元组的每个元素,并返回
std::元组
结果。实现非常简单,但是问题是:这个函数应该返回什么类型?我使用的实现
std::make_tuple
. 然而,
here
std::forward_as_tuple
有人建议。
更具体地说,实现(为简洁起见,省略了对空元组的处理):
#include <cstddef>
#include <tuple>
#include <type_traits>
#include <utility>
template<class Fn, class Tuple, std::size_t... indices>
constexpr auto tuple_map_v(Fn fn, Tuple&& tuple, std::index_sequence<indices...>)
{
return std::make_tuple(fn(std::get<indices>(std::forward<Tuple>(tuple)))...);
// ^^^
}
template<class Fn, class Tuple, std::size_t... indices>
constexpr auto tuple_map_r(Fn fn, Tuple&& tuple, std::index_sequence<indices...>)
{
return std::forward_as_tuple(fn(std::get<indices>(std::forward<Tuple>(tuple)))...);
// ^^^
}
template<class Tuple, class Fn>
constexpr auto tuple_map_v(Fn fn, Tuple&& tuple)
{
return tuple_map_v(fn, std::forward<Tuple>(tuple),
std::make_index_sequence<std::tuple_size_v<std::remove_reference_t<Tuple>>>{});
}
template<class Tuple, class Fn>
constexpr auto tuple_map_r(Fn fn, Tuple&& tuple)
{
return tuple_map_r(fn, std::forward<Tuple>(tuple),
std::make_index_sequence<std::tuple_size_v<std::remove_reference_t<Tuple>>>{});
}
在案例1中,我们使用
std::创建元组
会破坏每一个论点的类型(
_v
在案例2中,我们使用
std::转发
保留参考文献(
_r
供参考)。这两种情况各有利弊。
-
悬垂的参考。
auto copy = [](auto x) { return x; };
auto const_id = [](const auto& x) -> decltype(auto) { return x; };
auto r1 = tuple_map_v(copy, std::make_tuple(1));
// OK, type of r1 is std::tuple<int>
auto r2 = tuple_map_r(copy, std::make_tuple(1));
// UB, type of r2 is std::tuple<int&&>
std::tuple<int> r3 = tuple_map_r(copy, std::make_tuple(1));
// Still UB
std::tuple<int> r4 = tuple_map_r(const_id, std::make_tuple(1));
// OK now
-
引用元组。
auto id = [](auto& x) -> decltype(auto) { return x; };
int a = 0, b = 0;
auto r1 = tuple_map_v(id, std::forward_as_tuple(a, b));
// Type of r1 is std::tuple<int, int>
++std::get<0>(r1);
// Increments a copy, a is still zero
auto r2 = tuple_map_r(id, std::forward_as_tuple(a, b));
// Type of r2 is std::tuple<int&, int&>
++std::get<0>(r2);
// OK, now a = 1
-
仅移动类型。
NonCopyable nc;
auto r1 = tuple_map_v(id, std::forward_as_tuple(nc));
// Does not compile without a copy constructor
auto r2 = tuple_map_r(id, std::forward_as_tuple(nc));
// OK, type of r2 is std::tuple<NonCopyable&>
-
参考文献
std::创建元组
.
auto id_ref = [](auto& x) { return std::reference_wrapper(x); };
NonCopyable nc;
auto r1 = tuple_map_v(id_ref, std::forward_as_tuple(nc));
// OK now, type of r1 is std::tuple<NonCopyable&>
auto r2 = tuple_map_v(id_ref, std::forward_as_tuple(a, b));
// OK, type of r2 is std::tuple<int&, int&>
(可能是我做错了什么,或者错过了重要的事情。)
看来
make_tuple
方法是:它不产生悬挂引用,仍然可以强制推断引用类型。你将如何实施
元组映射
(与之相关的陷阱是什么?)?