I have a template function defined for variadic templates of two kinds:
template<typename ...A>
void foo(std::shared_future<A>... args) {
// ...
}
template<typename ...A>
void foo(std::future<A>&... args) {
// ...
}
This works for foo(a, b, c)
if a
, b
and c
are either all futures, or all shared futures. How can I adapt this code to work for any mix of both types templates, i.e. both shared and raw futures in this case?
You can first accept arbitrary types Futures...
and then use SFINAE to restrict them to std::[shared_]future
:
template<class>
struct is_future_or_shared_future : std::false_type {};
template<class T>
struct is_future_or_shared_future<std::future<T>> : std::true_type {};
template<class T>
struct is_future_or_shared_future<std::shared_future<T>> : std::true_type {};
template<class... Futures, typename = std::enable_if_t<
std::conjunction_v<is_future_or_shared_future<Futures>...>>>
void foo(Futures&... args) {
// ...
}
If you want to take both lvalues and rvalues, use forwarding references:
template<class T>
using remove_cvref_t = std::remove_cv_t<std::remove_reference_t<T>>;
template<class... Futures, typename = std::enable_if_t<
std::conjunction_v<is_future_or_shared_future<remove_cvref_t<Futures>>...>>>
void foo(Futures&&... args) {
// ...
}
To access the inner type you can use a traits class:
template<class>
struct inner_type;
template<class T>
struct inner_type<std::future<T>> {
using type = T;
};
template<class T>
struct inner_type<std::shared_future<T>> {
using type = T;
};
and then write:
typename B = std::result_of_t<
F(typename inner_type<remove_cvref_t<Futures>>::type...)>;