将函数应用于元组的每个元素
Applying a function to each element of a tuple
给定一个类似std::tuple
的对象(即具有定义的tuple_size
和get
语义)和一个一元函子对象ftor
,我希望能够在类tuple
对象的每个元素上调用ftor
。
如果我忽略返回值,我知道 int 数组技巧:
namespace details {
template <typename Ftor, typename Tuple, size_t... Is>
void apply_unary(Ftor&& ftor, Tuple&& tuple, std::index_sequence<Is...>) {
using std::get;
int arr[] = { (ftor(get<Is>(std::forward<Tuple>(tuple))), void(), 0)... };
}
} // namespace details
template <typename Ftor, typename Tuple>
void apply_unary(Ftor&& ftor, Tuple&& tuple) {
details::apply_unary(std::forward<Ftor>(ftor),
std::forward<Tuple>(tuple),
std::make_index_sequence<std::tuple_size<Tuple>::value> {});
}
如果我想要返回值,我可以将int []
技巧替换为调用 std::make_tuple
并返回它。前提是对ftor
对象的调用都没有void
返回值,这将起作用......
因此,我的问题是:考虑到我想获取呼叫的结果,如何处理可能返回void
的呼叫?
唯一的要求是我应该以元组的形式获取结果,并能够分辨出哪个调用导致所述结果元组的哪个元素。
正如 @Jarod42 所建议的,用一个额外的层来包装调用,该层负责用虚拟结构替换 void 返回将解决问题:
struct no_return {};
namespace details {
template <typename Ftor, typename Arg>
auto call(Ftor&& ftor, Arg&& arg)
-> std::enable_if_t<std::is_void<decltype(std::forward<Ftor>(ftor)(std::forward<Arg>(arg)))>::value, no_return> {
std::forward<Ftor>(ftor)(std::forward<Arg>(arg));
return no_return {};
}
template <typename Ftor, typename Arg>
auto call(Ftor&& ftor, Arg&& arg)
-> std::enable_if_t<!std::is_void<decltype(std::forward<Ftor>(ftor)(std::forward<Arg>(arg)))>::value, decltype(std::forward<Ftor>(ftor)(std::forward<Arg>(arg)))> {
return std::forward<Ftor>(ftor)(std::forward<Arg>(arg));
}
template <typename Ftor, typename Tuple, size_t... Is>
auto apply_unary(Ftor&& ftor, Tuple&& tuple, std::index_sequence<Is...>) {
using std::get;
return std::tuple<decltype(call(ftor, get<Is>(std::forward<Tuple>(tuple))))...> { call(ftor, get<Is>(std::forward<Tuple>(tuple)))... } ;
}
} // namespace details
template <typename Ftor, typename Tuple>
auto apply_unary(Ftor&& ftor, Tuple&& tuple) {
return details::apply_unary(std::forward<Ftor>(ftor),
std::forward<Tuple>(tuple),
std::make_index_sequence<std::tuple_size<std::decay_t<Tuple> >::value> {});
}
现场演示可在 Coliru 上获得
我使用 SFINAE 来区分两个重载。它看起来有点丑,所以如果你有任何改进建议......我都听见了!
另一种方式:
namespace details {
struct apply_unary_helper_t {};
template<class T>
T&& operator,(T&& t, apply_unary_helper_t) { // Keep the non-void result.
return std::forward<T>(t);
}
template <typename Ftor, typename Tuple, size_t... Is>
void apply_unary(Ftor&& ftor, Tuple&& tuple, std::index_sequence<Is...>) {
auto r = {(ftor(std::get<Is>(std::forward<Tuple>(tuple))), apply_unary_helper_t{})...};
static_cast<void>(r); // Suppress unused variable warning.
}
} // namespace details
template <typename Ftor, typename Tuple>
void apply_unary(Ftor&& ftor, Tuple&& tuple) {
details::apply_unary(std::forward<Ftor>(ftor),
std::forward<Tuple>(tuple),
std::make_index_sequence<std::tuple_size<std::remove_reference_t<Tuple>>::value> {});
}
在上面,它operator,
适用于ftor
和apply_unary_helper_t
的结果。如果ftor
的结果是void
,那么r
是std::initializer_list<details::apply_unary_helper_t>
的,否则r
是你可以利用的std::initializer_list<decltype(ftor(...))>
。
相关文章:
- 在C++中,如何通过几种类型从元组中选择多个元素
- 如何基于元组元素进行递归?
- 如何从标准::元组中删除元素?
- 元组元素是只读的?
- c++:交换向量中所有元组的第一个和第二个元素
- 我无法在用forward_as_tuple创建的元组中按类型访问元素
- 将函数应用于元组中的每个元素,将每个元素强制转换为类型包中的不同类型,然后作为参数包传递
- 如何获取元组的元素
- 如何使用返回第 n 个元素的方法创建元组
- 用一个额外的元素扩展 std::array 的每个 std::元组
- 如何处理元组中的元素
- 在 Hana 中满足谓词的元组元素的索引序列
- 如何部分专业化功能以用元组元素作为参数调用功能
- 匹配部分专用化以按类型替换元组元素
- 编译按映射类型获取元素的映射错误元组
- 仅当元组中存在该类型时,将功能应用于元组元素
- 获取std ::元组元素作为std ::变体
- 获取对元组元素的引用
- 检查元组是否包含特定类型的元素
- 比较元组中的和分类元素