类型安全 - all_of/ any_of/ none_of for std::tuple
type safety - all_of/ any_of/ none_of for std::tuple
所以我开始实现一些模仿STL算法行为的算法,但使用异构容器,又名std::tuple。
template<typename UnaryPredicate, typename Tuple>
bool all_of(UnaryPredicate&& p, Tuple&& t) noexcept
{
return std::apply([&p](auto&& ...xs){ return (p(std::forward<decltype(xs)>(xs)) && ...); }, std::forward<Tuple>(t));
}
template<typename UnaryPredicate, typename Tuple>
bool any_of(UnaryPredicate&& p, Tuple&& t) noexcept
{
return std::apply([&p](auto&& ...xs){ return (p(std::forward<decltype(xs)>(xs)) || ...); }, std::forward<Tuple>(t));
}
template<typename UnaryPredicate, typename Tuple>
bool none_of(UnaryPredicate&& p, Tuple&& t) noexcept
{
return std::apply([&p](auto&& ...xs){ return !(p(std::forward<decltype(xs)>(xs)) || ...); }, std::forward<Tuple>(t));
}
如果您使用返回布尔值的一元谓词,所有这些工作正常。但是,如果没有呢?如何确保 UnaryPredicate 在使用元组的每个元素调用时返回布尔值?另外,我如何检查UnaryPredicate是否实际上没有引发任何异常。
我知道有像"is_nothrow_invocable"和"invoke_result"这样的类型特征,但所有这些都需要元组包含的元素类型。我真的必须使用"algorithm_impl"模式吗?
namespace impl
{
template<typename UnaryPredicate, typename Tuple, auto ...Is>
bool all_of_impl(UnaryPredicate&& p, Tuple&& t, std::index_sequence<Is...>) noexcept
{
return std::apply([&p](auto&& ...xs){ return (p(std::forward<decltype(xs)>(xs)) && ...); }, std::forward<Tuple>(t));
}
}
template<typename UnaryPredicate, typename Tuple>
bool all_of(UnaryPredicate&& p, Tuple&& t) noexcept
{
return impl::all_of_impl(std::forward<UnaryPredicate>(p), std::forward<Tuple>(t), std::make_index_sequence<std::tuple_size_v<std::decay_t<Tuple>>>{});
}
现在我可以做这样的事情:
std::enable_if_t<std::conjunction_v<std::is_same<std::invoke_result_t<std::decay_t<UnaryPredicate>, std::tuple_element_t<Is, std::decay_t<Tuple>>>, bool>...>, bool>
但这真的是要走的路吗?
编辑:
好吧,一如既往,我把事情搞得太复杂了。我想我找到了一个可以接受的解决方案:
template<typename UnaryPredicate, typename Tuple>
struct helper;
template<typename UnaryPredicate, typename Tuple>
struct helper2;
template<typename UnaryPredicate, typename ...Ts>
struct helper<UnaryPredicate, std::tuple<Ts...>>
: std::bool_constant<std::conjunction_v<std::is_same<bool, std::invoke_result_t<std::decay_t<UnaryPredicate>, std::decay_t<Ts>>>...>>
{};
template<typename UnaryPredicate, typename ...Ts>
struct helper2<UnaryPredicate, std::tuple<Ts...>>
: std::bool_constant<std::conjunction_v<std::is_nothrow_invocable<std::decay_t<UnaryPredicate>, std::decay_t<Ts>>...>>
{};
template<typename UnaryPredicate, typename Tuple>
inline constexpr auto helper_v{ helper<UnaryPredicate, Tuple>::value };
template<typename UnaryPredicate, typename Tuple>
inline constexpr auto helper2_v{ helper2<UnaryPredicate, Tuple>::value };
template<typename UnaryPredicate, typename Tuple>
std::enable_if_t<helper_v<UnaryPredicate, Tuple>, bool> all_of(UnaryPredicate&& p, Tuple&& t) noexcept(helper2_v<UnaryPredicate, Tuple>)
{
return std::apply([&p](auto&& ...xs){ return (p(std::forward<decltype(xs)>(xs)) && ...); }, std::forward<Tuple>(t));
}
template<typename UnaryPredicate, typename Tuple>
std::enable_if_t<helper_v<UnaryPredicate, Tuple>, bool> any_of(UnaryPredicate&& p, Tuple&& t) noexcept(helper2_v<UnaryPredicate, Tuple>)
{
return std::apply([&p](auto&& ...xs){ return (p(std::forward<decltype(xs)>(xs)) || ...); }, std::forward<Tuple>(t));
}
template<typename UnaryPredicate, typename Tuple>
std::enable_if_t<helper_v<UnaryPredicate, Tuple>, bool> none_of(UnaryPredicate&& p, Tuple&& t) noexcept(helper2_v<UnaryPredicate, Tuple>)
{
return std::apply([&p](auto&& ...xs){ return !(p(std::forward<decltype(xs)>(xs)) || ...); }, std::forward<Tuple>(t));
}
#define RETURNS(...)
noexcept(noexcept(__VA_ARGS__))
-> decltype(__VA_ARGS__)
{ return __VA_ARGS__; }
template<class UnaryPredicate, class Tuple>
auto all_of(UnaryPredicate&& p, Tuple&& t)
RETURNS(
std::apply(
[&p](auto&& ...xs){
return (p(std::forward<decltype(xs)>(xs)) && ...);
},
std::forward<Tuple>(t)
)
)
等
我找到了一个比我之前的编辑:)更好的解决方案
#include <functional>
#include <iostream>
#include <tuple>
#include <type_traits>
#include <utility>
template<typename UnaryFunction, typename ...Types>
constexpr std::enable_if_t<std::conjunction_v<std::is_same<std::invoke_result_t<UnaryFunction, Types>, bool>...>, bool> AllOf(UnaryFunction&& p, std::tuple<Types...>&& t) noexcept(std::conjunction_v<std::is_nothrow_invocable<UnaryFunction, Types>...>)
{
return std::apply([&](auto&& ...xs) constexpr { return (p(std::forward<decltype(xs)>(xs)) && ...); }, std::forward<std::tuple<Types...>>(t));
}
template<typename UnaryFunction, typename ...Types>
constexpr std::enable_if_t<std::conjunction_v<std::is_same<std::invoke_result_t<UnaryFunction, Types>, bool>...>, bool> AnyOf(UnaryFunction&& p, std::tuple<Types...>&& t) noexcept(std::conjunction_v<std::is_nothrow_invocable<UnaryFunction, Types>...>)
{
return std::apply([&](auto&& ...xs) constexpr { return (p(std::forward<decltype(xs)>(xs)) || ...); }, std::forward<std::tuple<Types...>>(t));
}
template<typename UnaryFunction, typename ...Types>
constexpr std::enable_if_t<std::conjunction_v<std::is_same<std::invoke_result_t<UnaryFunction, Types>, bool>...>, bool> NoneOf(UnaryFunction&& p, std::tuple<Types...>&& t) noexcept(std::conjunction_v<std::is_nothrow_invocable<UnaryFunction, Types>...>)
{
return std::apply([&](auto&& ...xs) constexpr { return !(p(std::forward<decltype(xs)>(xs)) || ...); }, std::forward<std::tuple<Types...>>(t));
}
int main()
{
std::cout
<< std::boolalpha
<< AllOf([](auto&& x){ return x; }, std::make_tuple(true, true, true)) << "n"
<< AnyOf([](auto&& x){ return x; }, std::make_tuple(false, false, true)) << "n"
<< NoneOf([](auto&& x){ return x; }, std::make_tuple(false, false, false)) << "n";
}
相关文章:
- Usages of std::move
- Centos7 g++ "to_string is not in a member of std"
- 传递 std::vector of std::shared_ptr,而不是更新对象
- 从返回 std::optional of std::vector 的函数中获取结果到调用方
- PyBind11:返回对 std::vector of std::unique_ptr 的常量引用
- 是否可以使用 std::variant of std::variants
- What is the std::chrono::time_point equivalent of std::numer
- python equivalent of std::chrono::steady_clock::now();
- Strange behavior of std::vector<{QString,int*}>
- 如何在 std::map 中从 std::vector of std::p air 中获取输入?
- "terminate called after throwing an instance of std::invalid_argument' what(): stoi ?"
- Initialize std::array of std::array
- The uses of std::osyncstream?
- VC++ implementation of std::promise
- Return value of std::hash ofr (x86/x64)
- libc++ implementation of std::condition_variable_any
- constexpr version of ::std::function
- STD :: Min of std :: Chrono ::不同类型的持续时间
- 迭代一个巨大的 std::vector of std::vectors 并修改元素
- "Explicit specialization of std::iterator_traits<char *> after instantiation"(咕)