mirror of
https://github.com/Naios/continuable.git
synced 2025-12-06 16:56:44 +08:00
Use a std::apply style unpack
* Some cleanup
This commit is contained in:
parent
41c7cb008a
commit
f091cbb079
@ -852,8 +852,8 @@ constexpr auto make_ready_continuable(FirstResult&& first_result,
|
|||||||
std::forward<SecondResult>(second_result),
|
std::forward<SecondResult>(second_result),
|
||||||
std::forward<Rest>(rest)...)](
|
std::forward<Rest>(rest)...)](
|
||||||
auto&& promise) mutable {
|
auto&& promise) mutable {
|
||||||
detail::traits::unpack(result,
|
detail::traits::unpack(std::forward<decltype(promise)>(promise),
|
||||||
std::forward<decltype(promise)>(promise));
|
result);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -231,12 +231,14 @@ inline auto sequenced_unpack_invoker() {
|
|||||||
// the lambda.
|
// the lambda.
|
||||||
using Next = decltype(next_callback);
|
using Next = decltype(next_callback);
|
||||||
|
|
||||||
traits::unpack(std::move(result), [&](auto&&... types) {
|
traits::unpack(
|
||||||
|
[&](auto&&... types) {
|
||||||
/// TODO Add inplace resolution here
|
/// TODO Add inplace resolution here
|
||||||
|
|
||||||
invoke_no_except(std::forward<Next>(next_callback),
|
invoke_no_except(std::forward<Next>(next_callback),
|
||||||
std::forward<decltype(types)>(types)...);
|
std::forward<decltype(types)>(types)...);
|
||||||
});
|
},
|
||||||
|
std::move(result));
|
||||||
CONTINUABLE_BLOCK_TRY_END
|
CONTINUABLE_BLOCK_TRY_END
|
||||||
};
|
};
|
||||||
} // namespace decoration
|
} // namespace decoration
|
||||||
@ -277,12 +279,15 @@ void packed_dispatch(Executor&& executor, Invoker&& invoker, Args&&... args) {
|
|||||||
invoker = std::forward<Invoker>(invoker),
|
invoker = std::forward<Invoker>(invoker),
|
||||||
args = std::make_tuple(std::forward<Args>(args)...)
|
args = std::make_tuple(std::forward<Args>(args)...)
|
||||||
]() mutable {
|
]() mutable {
|
||||||
traits::unpack(std::move(args), [&](auto&&... captured_args) {
|
traits::unpack(
|
||||||
|
[&](auto&&... captured_args) {
|
||||||
// Just use the packed dispatch method which dispatches the work on
|
// Just use the packed dispatch method which dispatches the work on
|
||||||
// the current thread.
|
// the current thread.
|
||||||
packed_dispatch(types::this_thread_executor_tag{}, std::move(invoker),
|
packed_dispatch(
|
||||||
|
types::this_thread_executor_tag{}, std::move(invoker),
|
||||||
std::forward<decltype(captured_args)>(captured_args)...);
|
std::forward<decltype(captured_args)>(captured_args)...);
|
||||||
});
|
},
|
||||||
|
std::move(args));
|
||||||
};
|
};
|
||||||
|
|
||||||
// Pass the work callable object to the executor
|
// Pass the work callable object to the executor
|
||||||
|
|||||||
@ -149,9 +149,11 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
auto unbox() && {
|
auto unbox() && {
|
||||||
return traits::unpack(unpack_lazy(std::move(args_)), [](auto&&... args) {
|
return traits::unpack(
|
||||||
|
[](auto&&... args) {
|
||||||
return spread_this(std::forward<decltype(args)>(args)...);
|
return spread_this(std::forward<decltype(args)>(args)...);
|
||||||
});
|
},
|
||||||
|
unpack_lazy(std::move(args_)));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -208,8 +210,8 @@ template <typename... Args, typename Callback, typename Data>
|
|||||||
constexpr auto finalize_impl(traits::identity<std::tuple<Args...>>,
|
constexpr auto finalize_impl(traits::identity<std::tuple<Args...>>,
|
||||||
Callback&& callback, Data&& data) {
|
Callback&& callback, Data&& data) {
|
||||||
// Call the final callback with the cleaned result
|
// Call the final callback with the cleaned result
|
||||||
return traits::unpack(unbox_continuables(std::forward<Data>(data)),
|
return traits::unpack(std::forward<Callback>(callback),
|
||||||
std::forward<Callback>(callback));
|
unbox_continuables(std::forward<Data>(data)));
|
||||||
}
|
}
|
||||||
|
|
||||||
struct hint_mapper {
|
struct hint_mapper {
|
||||||
|
|||||||
@ -61,7 +61,7 @@ auto sequential_connect(Left&& left, Right&& right) {
|
|||||||
return std::move(right).then([previous = std::make_tuple(
|
return std::move(right).then([previous = std::make_tuple(
|
||||||
std::forward<decltype(args)>(args)...)](
|
std::forward<decltype(args)>(args)...)](
|
||||||
auto&&... args) mutable {
|
auto&&... args) mutable {
|
||||||
return traits::merge(
|
return std::tuple_cat(
|
||||||
std::move(previous),
|
std::move(previous),
|
||||||
std::make_tuple(std::forward<decltype(args)>(args)...));
|
std::make_tuple(std::forward<decltype(args)>(args)...));
|
||||||
});
|
});
|
||||||
|
|||||||
@ -56,7 +56,7 @@ template <typename... LeftArgs, typename... RightArgs>
|
|||||||
auto chain_connection(std::tuple<LeftArgs...> leftPack,
|
auto chain_connection(std::tuple<LeftArgs...> leftPack,
|
||||||
std::tuple<RightArgs...> rightPack) {
|
std::tuple<RightArgs...> rightPack) {
|
||||||
|
|
||||||
return traits::merge(std::move(leftPack), std::move(rightPack));
|
return std::tuple_cat(std::move(leftPack), std::move(rightPack));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Normalizes a continuation to a tuple holding an arbitrary count of
|
/// Normalizes a continuation to a tuple holding an arbitrary count of
|
||||||
|
|||||||
@ -58,6 +58,8 @@
|
|||||||
#define CONTINUABLE_HAS_CXX17_VOID_T
|
#define CONTINUABLE_HAS_CXX17_VOID_T
|
||||||
#else
|
#else
|
||||||
// Generic feature detection based on __has_feature
|
// Generic feature detection based on __has_feature
|
||||||
|
// and other preprocessor definitions based on:
|
||||||
|
// http://en.cppreference.com/w/User:D41D8CD98F/feature_testing_macros
|
||||||
#if defined(__has_feature)
|
#if defined(__has_feature)
|
||||||
#if !defined(CONTINUABLE_HAS_CXX17_CONSTEXPR_IF) && \
|
#if !defined(CONTINUABLE_HAS_CXX17_CONSTEXPR_IF) && \
|
||||||
__has_feature(cxx_if_constexpr)
|
__has_feature(cxx_if_constexpr)
|
||||||
|
|||||||
@ -77,14 +77,15 @@ struct promisify_helper {
|
|||||||
auto&& promise) mutable {
|
auto&& promise) mutable {
|
||||||
|
|
||||||
traits::unpack(
|
traits::unpack(
|
||||||
std::move(args), [promise = std::forward<decltype(promise)>(promise)](
|
[promise = std::forward<decltype(promise)>(promise)](
|
||||||
auto&&... args) mutable {
|
auto&&... args) mutable {
|
||||||
Evaluator<std::decay_t<decltype(promise)>> evaluator{
|
Evaluator<std::decay_t<decltype(promise)>> evaluator{
|
||||||
std::move(promise)};
|
std::move(promise)};
|
||||||
|
|
||||||
util::invoke(std::forward<decltype(args)>(args)...,
|
util::invoke(std::forward<decltype(args)>(args)...,
|
||||||
std::move(evaluator));
|
std::move(evaluator));
|
||||||
});
|
},
|
||||||
|
std::move(args));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@ -32,7 +32,6 @@
|
|||||||
#define CONTINUABLE_DETAIL_TRAITS_HPP_INCLUDED
|
#define CONTINUABLE_DETAIL_TRAITS_HPP_INCLUDED
|
||||||
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <initializer_list>
|
|
||||||
#include <tuple>
|
#include <tuple>
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
@ -184,108 +183,33 @@ constexpr auto static_if(Type&& type, Check&& check,
|
|||||||
std::forward<FalseCallback>(falseCallback));
|
std::forward<FalseCallback>(falseCallback));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Calls the given unpacker with the content of the given sequence
|
namespace detail {
|
||||||
template <typename U, std::size_t... I>
|
|
||||||
constexpr decltype(auto) unpack(std::integer_sequence<std::size_t, I...>,
|
|
||||||
U&& unpacker) {
|
|
||||||
return std::forward<U>(unpacker)(std::integral_constant<std::size_t, I>{}...);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Calls the given unpacker with the content of the given sequenceable
|
/// Calls the given unpacker with the content of the given sequenceable
|
||||||
template <typename F, typename U, std::size_t... I>
|
template <typename U, typename F, std::size_t... I>
|
||||||
constexpr auto unpack(F&& first_sequenceable, U&& unpacker,
|
constexpr auto unpack_impl(U&& unpacker, F&& first_sequenceable,
|
||||||
std::integer_sequence<std::size_t, I...>)
|
std::integer_sequence<std::size_t, I...>)
|
||||||
-> decltype(std::forward<U>(unpacker)(
|
-> decltype(std::forward<U>(unpacker)(
|
||||||
get<I>(std::forward<F>(first_sequenceable))...)) {
|
std::get<I>(std::forward<F>(first_sequenceable))...)) {
|
||||||
(void)first_sequenceable;
|
(void)first_sequenceable;
|
||||||
return std::forward<U>(unpacker)(
|
return std::forward<U>(unpacker)(
|
||||||
get<I>(std::forward<F>(first_sequenceable))...);
|
std::get<I>(std::forward<F>(first_sequenceable))...);
|
||||||
}
|
|
||||||
/// Calls the given unpacker with the content of the given sequenceable
|
|
||||||
template <typename F, typename S, typename U, std::size_t... If,
|
|
||||||
std::size_t... Is>
|
|
||||||
constexpr auto unpack(F&& first_sequenceable, S&& second_sequenceable,
|
|
||||||
U&& unpacker, std::integer_sequence<std::size_t, If...>,
|
|
||||||
std::integer_sequence<std::size_t, Is...>)
|
|
||||||
-> decltype(std::forward<U>(unpacker)(
|
|
||||||
get<If>(std::forward<F>(first_sequenceable))...,
|
|
||||||
get<Is>(std::forward<S>(second_sequenceable))...)) {
|
|
||||||
(void)first_sequenceable;
|
|
||||||
(void)second_sequenceable;
|
|
||||||
return std::forward<U>(unpacker)(
|
|
||||||
get<If>(std::forward<F>(first_sequenceable))...,
|
|
||||||
get<Is>(std::forward<S>(second_sequenceable))...);
|
|
||||||
}
|
|
||||||
/// Calls the given unpacker with the content of the given sequenceable
|
|
||||||
template <typename F, typename U>
|
|
||||||
constexpr auto unpack(F&& first_sequenceable, U&& unpacker)
|
|
||||||
-> decltype(unpack(std::forward<F>(first_sequenceable),
|
|
||||||
std::forward<U>(unpacker),
|
|
||||||
sequence_of(identify<decltype(first_sequenceable)>{}))) {
|
|
||||||
return unpack(std::forward<F>(first_sequenceable), std::forward<U>(unpacker),
|
|
||||||
sequence_of(identify<decltype(first_sequenceable)>{}));
|
|
||||||
}
|
|
||||||
/// Calls the given unpacker with the content of the given sequenceables
|
|
||||||
template <typename F, typename S, typename U>
|
|
||||||
constexpr auto unpack(F&& first_sequenceable, S&& second_sequenceable,
|
|
||||||
U&& unpacker)
|
|
||||||
-> decltype(unpack(std::forward<F>(first_sequenceable),
|
|
||||||
std::forward<S>(second_sequenceable),
|
|
||||||
std::forward<U>(unpacker),
|
|
||||||
sequence_of(identity_of(first_sequenceable)),
|
|
||||||
sequence_of(identity_of(second_sequenceable)))) {
|
|
||||||
return unpack(std::forward<F>(first_sequenceable),
|
|
||||||
std::forward<S>(second_sequenceable), std::forward<U>(unpacker),
|
|
||||||
sequence_of(identity_of(first_sequenceable)),
|
|
||||||
sequence_of(identity_of(second_sequenceable)));
|
|
||||||
}
|
}
|
||||||
|
} // namespace detail
|
||||||
|
|
||||||
/// Adds the given type at the back of the left sequenceable
|
/// Calls the given callable object with the content of the given sequenceable
|
||||||
template <typename Left, typename Element>
|
///
|
||||||
constexpr auto push(Left&& left, Element&& element) {
|
/// \note We can't use std::apply here since this implementation is SFINAE
|
||||||
return unpack(std::forward<Left>(left), [&](auto&&... args) {
|
/// aware and the std version not! This would lead to compilation errors.
|
||||||
return std::make_tuple(std::forward<decltype(args)>(args)...,
|
template <typename Callable, typename TupleLike,
|
||||||
std::forward<Element>(element));
|
typename Sequence = std::make_index_sequence<
|
||||||
});
|
std::tuple_size<std::decay_t<TupleLike>>::value>>
|
||||||
}
|
constexpr auto unpack(Callable&& obj, TupleLike&& tuple_like)
|
||||||
|
-> decltype(detail::unpack_impl(std::forward<Callable>(obj),
|
||||||
|
std::forward<TupleLike>(tuple_like),
|
||||||
|
Sequence{})) {
|
||||||
|
|
||||||
/// Adds the element to the back of the identity
|
return detail::unpack_impl(std::forward<Callable>(obj),
|
||||||
template <typename... Args, typename Element>
|
std::forward<TupleLike>(tuple_like), Sequence{});
|
||||||
constexpr auto push(identity<Args...>, identity<Element>) noexcept {
|
|
||||||
return identity<Args..., Element>{};
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Removes the first element from the identity
|
|
||||||
template <typename First, typename... Rest>
|
|
||||||
constexpr auto pop_first(identity<First, Rest...>) noexcept {
|
|
||||||
return identity<Rest...>{};
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the merged sequence
|
|
||||||
template <typename Left>
|
|
||||||
constexpr auto merge(Left&& left) {
|
|
||||||
return std::forward<Left>(left);
|
|
||||||
}
|
|
||||||
/// Merges the left sequenceable with the right ones
|
|
||||||
template <typename Left, typename Right, typename... Rest>
|
|
||||||
constexpr auto merge(Left&& left, Right&& right, Rest&&... rest) {
|
|
||||||
// Merge the left with the right sequenceable and
|
|
||||||
// merge the result with the rest.
|
|
||||||
return merge(unpack(std::forward<Left>(left), std::forward<Right>(right),
|
|
||||||
[&](auto&&... args) {
|
|
||||||
// Maybe use: template <template<typename...> class T,
|
|
||||||
// typename... Args>
|
|
||||||
return std::make_tuple(
|
|
||||||
std::forward<decltype(args)>(args)...);
|
|
||||||
}),
|
|
||||||
std::forward<Rest>(rest)...);
|
|
||||||
}
|
|
||||||
/// Merges the left identity with the right ones
|
|
||||||
template <typename... LeftArgs, typename... RightArgs, typename... Rest>
|
|
||||||
constexpr auto merge(identity<LeftArgs...> /*left*/,
|
|
||||||
identity<RightArgs...> /*right*/, Rest&&... rest) {
|
|
||||||
return merge(identity<LeftArgs..., RightArgs...>{},
|
|
||||||
std::forward<Rest>(rest)...);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace detail {
|
namespace detail {
|
||||||
|
|||||||
@ -520,7 +520,7 @@ struct resume_state_callable {
|
|||||||
template <typename Frame, typename State>
|
template <typename Frame, typename State>
|
||||||
void resume_traversal_callable<Frame, State>::operator()() {
|
void resume_traversal_callable<Frame, State>::operator()() {
|
||||||
auto hierarchy = std::tuple_cat(std::make_tuple(frame_), state_);
|
auto hierarchy = std::tuple_cat(std::make_tuple(frame_), state_);
|
||||||
traits::unpack(std::move(hierarchy), resume_state_callable{});
|
traits::unpack(resume_state_callable{}, std::move(hierarchy));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Gives access to types related to the traversal frame
|
/// Gives access to types related to the traversal frame
|
||||||
|
|||||||
@ -192,10 +192,10 @@ struct flat_arraylizer {
|
|||||||
template <typename C, typename... T>
|
template <typename C, typename... T>
|
||||||
constexpr auto apply_spread_impl(std::true_type, C&& callable, T&&... args)
|
constexpr auto apply_spread_impl(std::true_type, C&& callable, T&&... args)
|
||||||
-> decltype(
|
-> decltype(
|
||||||
traits::unpack(std::tuple_cat(undecorate(std::forward<T>(args))...),
|
traits::unpack(std::forward<C>(callable),
|
||||||
std::forward<C>(callable))) {
|
std::tuple_cat(undecorate(std::forward<T>(args))...))) {
|
||||||
return traits::unpack(std::tuple_cat(undecorate(std::forward<T>(args))...),
|
return traits::unpack(std::forward<C>(callable),
|
||||||
std::forward<C>(callable));
|
std::tuple_cat(undecorate(std::forward<T>(args))...));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Use the linear instantiation for variadic packs which don't
|
/// Use the linear instantiation for variadic packs which don't
|
||||||
@ -630,14 +630,14 @@ struct tuple_like_remapper<
|
|||||||
/// different types.
|
/// different types.
|
||||||
template <typename Strategy, typename T, typename M>
|
template <typename Strategy, typename T, typename M>
|
||||||
auto remap(Strategy, T&& container, M&& mapper) -> decltype(traits::unpack(
|
auto remap(Strategy, T&& container, M&& mapper) -> decltype(traits::unpack(
|
||||||
std::forward<T>(container),
|
|
||||||
std::declval<tuple_like_remapper<Strategy, typename std::decay<M>::type,
|
std::declval<tuple_like_remapper<Strategy, typename std::decay<M>::type,
|
||||||
typename std::decay<T>::type>>())) {
|
typename std::decay<T>::type>>(),
|
||||||
|
std::forward<T>(container))) {
|
||||||
return traits::unpack(
|
return traits::unpack(
|
||||||
std::forward<T>(container),
|
|
||||||
tuple_like_remapper<Strategy, typename std::decay<M>::type,
|
tuple_like_remapper<Strategy, typename std::decay<M>::type,
|
||||||
typename std::decay<T>::type>{
|
typename std::decay<T>::type>{
|
||||||
std::forward<M>(mapper)});
|
std::forward<M>(mapper)},
|
||||||
|
std::forward<T>(container));
|
||||||
}
|
}
|
||||||
} // end namespace tuple_like_remapping
|
} // end namespace tuple_like_remapping
|
||||||
|
|
||||||
|
|||||||
@ -49,27 +49,27 @@ constexpr void unused(T&&...) noexcept {
|
|||||||
}
|
}
|
||||||
|
|
||||||
namespace detail {
|
namespace detail {
|
||||||
|
template <typename T, std::size_t... I>
|
||||||
|
auto forward_except_last_impl(T&& tuple,
|
||||||
|
std::integer_sequence<std::size_t, I...>) {
|
||||||
|
(void)tuple;
|
||||||
|
return std::forward_as_tuple(std::get<I>(std::forward<T>(tuple))...);
|
||||||
|
}
|
||||||
|
|
||||||
/// Forwards every element in the tuple except the last one
|
/// Forwards every element in the tuple except the last one
|
||||||
template <typename T>
|
template <typename T>
|
||||||
auto forward_except_last(T&& sequenceable) {
|
auto forward_except_last(T&& sequenceable) {
|
||||||
constexpr auto const size = pack_size_of(traits::identify<T>()) - 1U;
|
constexpr auto const size = pack_size_of(traits::identify<T>()) - 1U;
|
||||||
constexpr auto const sequence = std::make_index_sequence<size>();
|
constexpr auto const sequence = std::make_index_sequence<size>();
|
||||||
|
|
||||||
return traits::unpack(std::forward<T>(sequenceable),
|
return forward_except_last_impl(std::forward<T>(sequenceable), sequence);
|
||||||
[](auto&&... args) {
|
|
||||||
return std::forward_as_tuple(
|
|
||||||
std::forward<decltype(args)>(args)...);
|
|
||||||
},
|
|
||||||
sequence);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// We are able to call the callable with the arguments given in the tuple
|
/// We are able to call the callable with the arguments given in the tuple
|
||||||
template <typename T, typename... Args>
|
template <typename T, typename... Args>
|
||||||
auto partial_invoke_impl(std::true_type, T&& callable,
|
auto partial_invoke_impl(std::true_type, T&& callable,
|
||||||
std::tuple<Args...> args) {
|
std::tuple<Args...> args) {
|
||||||
return traits::unpack(std::move(args), [&](auto&&... arg) {
|
return traits::unpack(std::forward<T>(callable), std::move(args));
|
||||||
return std::forward<T>(callable)(std::forward<decltype(arg)>(arg)...);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// We were unable to call the callable with the arguments in the tuple.
|
/// We were unable to call the callable with the arguments in the tuple.
|
||||||
|
|||||||
@ -33,21 +33,18 @@ using namespace cti::detail;
|
|||||||
TEST(regression_tests, are_multiple_args_mergeable) {
|
TEST(regression_tests, are_multiple_args_mergeable) {
|
||||||
{
|
{
|
||||||
auto tp = std::make_tuple(1, 2, 3);
|
auto tp = std::make_tuple(1, 2, 3);
|
||||||
traits::merge(tp, tp, tp, tp, tp);
|
std::tuple_cat(tp, tp, tp, tp, tp);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto tp2 = traits::merge(std::make_tuple(), std::make_tuple(1),
|
auto tp2 = std::tuple_cat(std::make_tuple(), std::make_tuple(1),
|
||||||
std::make_tuple(1, 2), std::make_tuple(1, 2, 3),
|
std::make_tuple(1, 2), std::make_tuple(1, 2, 3),
|
||||||
std::make_tuple(1, 2, 3, 4));
|
std::make_tuple(1, 2, 3, 4));
|
||||||
|
|
||||||
auto count = traits::unpack(tp2, [](auto... args) {
|
auto count = traits::unpack(
|
||||||
|
[](auto... args) {
|
||||||
std::vector<int> v{args...};
|
std::vector<int> v{args...};
|
||||||
return std::accumulate(v.begin(), v.end(), 0);
|
return std::accumulate(v.begin(), v.end(), 0);
|
||||||
});
|
},
|
||||||
|
tp2);
|
||||||
EXPECT_EQ(count, 20);
|
EXPECT_EQ(count, 20);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(recursion_tests, are_noncopyable_mergeable) {
|
|
||||||
std::tuple<util::non_copyable> nc1, nc2, nc3;
|
|
||||||
traits::merge(std::move(nc1), std::move(nc2), std::move(nc3));
|
|
||||||
}
|
|
||||||
|
|||||||
@ -49,9 +49,11 @@ template <typename... Args>
|
|||||||
auto supplier_of(Args&&... args) {
|
auto supplier_of(Args&&... args) {
|
||||||
return [values = std::make_tuple(std::forward<Args>(args)...)](
|
return [values = std::make_tuple(std::forward<Args>(args)...)](
|
||||||
auto&& promise) mutable {
|
auto&& promise) mutable {
|
||||||
cti::detail::traits::unpack(std::move(values), [&](auto&&... passed) {
|
cti::detail::traits::unpack(
|
||||||
|
[&](auto&&... passed) {
|
||||||
promise.set_value(std::forward<decltype(passed)>(passed)...);
|
promise.set_value(std::forward<decltype(passed)>(passed)...);
|
||||||
});
|
},
|
||||||
|
std::move(values));
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user