[英]Applying a function to each element of a tuple
給定一個tuple_size
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> {});
}
如果我想要返回值,我可以用std::make_tuple
調用替換int []
技巧,然后返回。 只要沒有對ftor
對象的調用都有void
值返回值, ftor
。
因此我的問題是:考慮到我想得到調用的結果,我該如何處理可能返回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(...))>
,您可以使用它。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.