1
0
forked from boostorg/mp11

Update mp_fold to be SFINAE-friendly (for up to 9 elements)

This commit is contained in:
Peter Dimov
2023-03-24 05:13:48 +02:00
parent b937a27f7e
commit f16707f6e9
5 changed files with 277 additions and 99 deletions

View File

@ -0,0 +1,119 @@
#ifndef BOOST_MP11_DETAIL_MP_DEFER_HPP_INCLUDED
#define BOOST_MP11_DETAIL_MP_DEFER_HPP_INCLUDED
// Copyright 2015-2020, 2023 Peter Dimov
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
#include <boost/mp11/integral.hpp>
#include <boost/mp11/detail/config.hpp>
namespace boost
{
namespace mp11
{
// mp_if, mp_if_c
namespace detail
{
template<bool C, class T, class... E> struct mp_if_c_impl
{
};
template<class T, class... E> struct mp_if_c_impl<true, T, E...>
{
using type = T;
};
template<class T, class E> struct mp_if_c_impl<false, T, E>
{
using type = E;
};
} // namespace detail
template<bool C, class T, class... E> using mp_if_c = typename detail::mp_if_c_impl<C, T, E...>::type;
template<class C, class T, class... E> using mp_if = typename detail::mp_if_c_impl<static_cast<bool>(C::value), T, E...>::type;
// mp_valid
#if BOOST_MP11_WORKAROUND( BOOST_MP11_INTEL, != 0 ) // tested at 1800
// contributed by Roland Schulz in https://github.com/boostorg/mp11/issues/17
namespace detail
{
template<class...> using void_t = void;
template<class, template<class...> class F, class... T>
struct mp_valid_impl: mp_false {};
template<template<class...> class F, class... T>
struct mp_valid_impl<void_t<F<T...>>, F, T...>: mp_true {};
} // namespace detail
template<template<class...> class F, class... T> using mp_valid = typename detail::mp_valid_impl<void, F, T...>;
#else
// implementation by Bruno Dutra (by the name is_evaluable)
namespace detail
{
template<template<class...> class F, class... T> struct mp_valid_impl
{
template<template<class...> class G, class = G<T...>> static mp_true check(int);
template<template<class...> class> static mp_false check(...);
using type = decltype(check<F>(0));
};
} // namespace detail
template<template<class...> class F, class... T> using mp_valid = typename detail::mp_valid_impl<F, T...>::type;
#endif
template<class Q, class... T> using mp_valid_q = mp_valid<Q::template fn, T...>;
// mp_defer
namespace detail
{
template<template<class...> class F, class... T> struct mp_defer_impl
{
using type = F<T...>;
};
struct mp_no_type
{
};
#if BOOST_MP11_WORKAROUND( BOOST_MP11_CUDA, >= 9000000 && BOOST_MP11_CUDA < 10000000 )
template<template<class...> class F, class... T> struct mp_defer_cuda_workaround
{
using type = mp_if<mp_valid<F, T...>, detail::mp_defer_impl<F, T...>, detail::mp_no_type>;
};
#endif
} // namespace detail
#if BOOST_MP11_WORKAROUND( BOOST_MP11_CUDA, >= 9000000 && BOOST_MP11_CUDA < 10000000 )
template<template<class...> class F, class... T> using mp_defer = typename detail::mp_defer_cuda_workaround< F, T...>::type;
#else
template<template<class...> class F, class... T> using mp_defer = mp_if<mp_valid<F, T...>, detail::mp_defer_impl<F, T...>, detail::mp_no_type>;
#endif
} // namespace mp11
} // namespace boost
#endif // #ifndef BOOST_MP11_DETAIL_MP_DEFER_HPP_INCLUDED

View File

@ -9,6 +9,7 @@
// http://www.boost.org/LICENSE_1_0.txt
#include <boost/mp11/detail/config.hpp>
#include <boost/mp11/detail/mp_defer.hpp>
namespace boost
{
@ -41,12 +42,113 @@ template<template<class...> class L, class V, template<class...> class F> struct
#endif
template<template<class...> class L, class T1, class... T, class V, template<class...> class F> struct mp_fold_impl<L<T1, T...>, V, F>
//
template<class V, template<class...> class F> struct mp_fold_Q1
{
using type = typename mp_fold_impl<L<T...>, F<V, T1>, F>::type;
template<class T1>
using fn = F<V, T1>;
};
template<template<class...> class L, class T1, class T2, class T3, class T4, class T5, class T6, class T7, class T8, class T9, class T10, class... T, class V, template<class...> class F> struct mp_fold_impl<L<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T...>, V, F>
template<class V, template<class...> class F> struct mp_fold_Q2
{
template<class T1, class T2>
using fn = F<F<V, T1>, T2>;
};
template<class V, template<class...> class F> struct mp_fold_Q3
{
template<class T1, class T2, class T3>
using fn = F<F<F<V, T1>, T2>, T3>;
};
template<class V, template<class...> class F> struct mp_fold_Q4
{
template<class T1, class T2, class T3, class T4>
using fn = F<F<F<F<V, T1>, T2>, T3>, T4>;
};
template<class V, template<class...> class F> struct mp_fold_Q5
{
template<class T1, class T2, class T3, class T4, class T5>
using fn = F<F<F<F<F<V, T1>, T2>, T3>, T4>, T5>;
};
template<class V, template<class...> class F> struct mp_fold_Q6
{
template<class T1, class T2, class T3, class T4, class T5, class T6>
using fn = F<F<F<F<F<F<V, T1>, T2>, T3>, T4>, T5>, T6>;
};
template<class V, template<class...> class F> struct mp_fold_Q7
{
template<class T1, class T2, class T3, class T4, class T5, class T6, class T7>
using fn = F<F<F<F<F<F<F<V, T1>, T2>, T3>, T4>, T5>, T6>, T7>;
};
template<class V, template<class...> class F> struct mp_fold_Q8
{
template<class T1, class T2, class T3, class T4, class T5, class T6, class T7, class T8>
using fn = F<F<F<F<F<F<F<F<V, T1>, T2>, T3>, T4>, T5>, T6>, T7>, T8>;
};
template<class V, template<class...> class F> struct mp_fold_Q9
{
template<class T1, class T2, class T3, class T4, class T5, class T6, class T7, class T8, class T9>
using fn = F<F<F<F<F<F<F<F<F<V, T1>, T2>, T3>, T4>, T5>, T6>, T7>, T8>, T9>;
};
//
template<template<class...> class L, class T1, class V, template<class...> class F>
struct mp_fold_impl<L<T1>, V, F>: mp_defer<mp_fold_Q1<V, F>::template fn, T1>
{
};
template<template<class...> class L, class T1, class T2, class V, template<class...> class F>
struct mp_fold_impl<L<T1, T2>, V, F>: mp_defer<mp_fold_Q2<V, F>::template fn, T1, T2>
{
};
template<template<class...> class L, class T1, class T2, class T3, class V, template<class...> class F>
struct mp_fold_impl<L<T1, T2, T3>, V, F>: mp_defer<mp_fold_Q3<V, F>::template fn, T1, T2, T3>
{
};
template<template<class...> class L, class T1, class T2, class T3, class T4, class V, template<class...> class F>
struct mp_fold_impl<L<T1, T2, T3, T4>, V, F>: mp_defer<mp_fold_Q4<V, F>::template fn, T1, T2, T3, T4>
{
};
template<template<class...> class L, class T1, class T2, class T3, class T4, class T5, class V, template<class...> class F>
struct mp_fold_impl<L<T1, T2, T3, T4, T5>, V, F>: mp_defer<mp_fold_Q5<V, F>::template fn, T1, T2, T3, T4, T5>
{
};
template<template<class...> class L, class T1, class T2, class T3, class T4, class T5, class T6, class V, template<class...> class F>
struct mp_fold_impl<L<T1, T2, T3, T4, T5, T6>, V, F>: mp_defer<mp_fold_Q6<V, F>::template fn, T1, T2, T3, T4, T5, T6>
{
};
template<template<class...> class L, class T1, class T2, class T3, class T4, class T5, class T6, class T7, class V, template<class...> class F>
struct mp_fold_impl<L<T1, T2, T3, T4, T5, T6, T7>, V, F>: mp_defer<mp_fold_Q7<V, F>::template fn, T1, T2, T3, T4, T5, T6, T7>
{
};
template<template<class...> class L, class T1, class T2, class T3, class T4, class T5, class T6, class T7, class T8, class V, template<class...> class F>
struct mp_fold_impl<L<T1, T2, T3, T4, T5, T6, T7, T8>, V, F>: mp_defer<mp_fold_Q8<V, F>::template fn, T1, T2, T3, T4, T5, T6, T7, T8>
{
};
template<template<class...> class L, class T1, class T2, class T3, class T4, class T5, class T6, class T7, class T8, class T9, class V, template<class...> class F>
struct mp_fold_impl<L<T1, T2, T3, T4, T5, T6, T7, T8, T9>, V, F>: mp_defer<mp_fold_Q9<V, F>::template fn, T1, T2, T3, T4, T5, T6, T7, T8, T9>
{
};
//
template<template<class...> class L, class T1, class T2, class T3, class T4, class T5, class T6, class T7, class T8, class T9, class T10, class... T, class V, template<class...> class F>
struct mp_fold_impl<L<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T...>, V, F>
{
using type = typename mp_fold_impl<L<T...>, F<F<F<F<F<F<F<F<F<F<V, T1>, T2>, T3>, T4>, T5>, T6>, T7>, T8>, T9>, T10>, F>::type;
};

View File

@ -13,6 +13,7 @@
#include <boost/mp11/detail/mp_fold.hpp>
#include <boost/mp11/detail/mp_front.hpp>
#include <boost/mp11/detail/mp_rename.hpp>
#include <boost/mp11/detail/mp_defer.hpp>
#include <boost/mp11/detail/config.hpp>
namespace boost
@ -33,104 +34,9 @@ template<class T> using mp_identity_t = typename mp_identity<T>::type;
template<class... T> struct mp_inherit: T... {};
// mp_if, mp_if_c
namespace detail
{
template<bool C, class T, class... E> struct mp_if_c_impl
{
};
template<class T, class... E> struct mp_if_c_impl<true, T, E...>
{
using type = T;
};
template<class T, class E> struct mp_if_c_impl<false, T, E>
{
using type = E;
};
} // namespace detail
template<bool C, class T, class... E> using mp_if_c = typename detail::mp_if_c_impl<C, T, E...>::type;
template<class C, class T, class... E> using mp_if = typename detail::mp_if_c_impl<static_cast<bool>(C::value), T, E...>::type;
// mp_valid
#if BOOST_MP11_WORKAROUND( BOOST_MP11_INTEL, != 0 ) // tested at 1800
// contributed by Roland Schulz in https://github.com/boostorg/mp11/issues/17
namespace detail
{
template<class...> using void_t = void;
template<class, template<class...> class F, class... T>
struct mp_valid_impl: mp_false {};
template<template<class...> class F, class... T>
struct mp_valid_impl<void_t<F<T...>>, F, T...>: mp_true {};
} // namespace detail
template<template<class...> class F, class... T> using mp_valid = typename detail::mp_valid_impl<void, F, T...>;
#else
// implementation by Bruno Dutra (by the name is_evaluable)
namespace detail
{
template<template<class...> class F, class... T> struct mp_valid_impl
{
template<template<class...> class G, class = G<T...>> static mp_true check(int);
template<template<class...> class> static mp_false check(...);
using type = decltype(check<F>(0));
};
} // namespace detail
template<template<class...> class F, class... T> using mp_valid = typename detail::mp_valid_impl<F, T...>::type;
#endif
template<class Q, class... T> using mp_valid_q = mp_valid<Q::template fn, T...>;
// mp_defer
namespace detail
{
template<template<class...> class F, class... T> struct mp_defer_impl
{
using type = F<T...>;
};
struct mp_no_type
{
};
#if BOOST_MP11_WORKAROUND( BOOST_MP11_CUDA, >= 9000000 && BOOST_MP11_CUDA < 10000000 )
template<template<class...> class F, class... T> struct mp_defer_cuda_workaround
{
using type = mp_if<mp_valid<F, T...>, detail::mp_defer_impl<F, T...>, detail::mp_no_type>;
};
#endif
} // namespace detail
#if BOOST_MP11_WORKAROUND( BOOST_MP11_CUDA, >= 9000000 && BOOST_MP11_CUDA < 10000000 )
template<template<class...> class F, class... T> using mp_defer = typename detail::mp_defer_cuda_workaround< F, T...>::type;
#else
template<template<class...> class F, class... T> using mp_defer = mp_if<mp_valid<F, T...>, detail::mp_defer_impl<F, T...>, detail::mp_no_type>;
#endif
// moved to detail/mp_defer.hpp
// mp_eval_if, mp_eval_if_c
namespace detail

View File

@ -88,6 +88,7 @@ run mp_find_if_q.cpp ;
run mp_reverse.cpp ;
run mp_fold.cpp ;
run mp_fold_q.cpp ;
run mp_fold_q_sf.cpp ;
run mp_reverse_fold.cpp ;
run mp_reverse_fold_q.cpp ;
run mp_unique.cpp ;

50
test/mp_fold_q_sf.cpp Normal file
View File

@ -0,0 +1,50 @@
// Copyright 2023 Peter Dimov
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
#include <boost/mp11/algorithm.hpp>
#include <boost/mp11/list.hpp>
#include <boost/mp11/integral.hpp>
#include <boost/core/lightweight_test_trait.hpp>
#include <type_traits>
#include <tuple>
using boost::mp11::mp_size_t;
struct Q
{
template<class N, class T> using fn = mp_size_t<N::value + sizeof(T)>;
};
int main()
{
using boost::mp11::mp_valid;
using boost::mp11::mp_fold_q;
using boost::mp11::mp_list;
BOOST_TEST_TRAIT_TRUE((mp_valid<mp_fold_q, mp_list<>, mp_size_t<0>, Q>));
BOOST_TEST_TRAIT_TRUE((mp_valid<mp_fold_q, mp_list<int>, mp_size_t<0>, Q>));
BOOST_TEST_TRAIT_TRUE((mp_valid<mp_fold_q, mp_list<int, int>, mp_size_t<0>, Q>));
BOOST_TEST_TRAIT_TRUE((mp_valid<mp_fold_q, mp_list<int, int, int>, mp_size_t<0>, Q>));
BOOST_TEST_TRAIT_TRUE((mp_valid<mp_fold_q, mp_list<int, int, int, int>, mp_size_t<0>, Q>));
BOOST_TEST_TRAIT_FALSE((mp_valid<mp_fold_q, mp_list<void>, mp_size_t<0>, Q>));
BOOST_TEST_TRAIT_FALSE((mp_valid<mp_fold_q, mp_list<int, void>, mp_size_t<0>, Q>));
BOOST_TEST_TRAIT_FALSE((mp_valid<mp_fold_q, mp_list<int, int, void>, mp_size_t<0>, Q>));
BOOST_TEST_TRAIT_FALSE((mp_valid<mp_fold_q, mp_list<int, int, int, void>, mp_size_t<0>, Q>));
#if !BOOST_MP11_WORKAROUND( BOOST_MP11_MSVC, < 1910 )
BOOST_TEST_TRAIT_FALSE((mp_valid<mp_fold_q, mp_list<void, int>, mp_size_t<0>, Q>));
BOOST_TEST_TRAIT_FALSE((mp_valid<mp_fold_q, mp_list<void, int, int>, mp_size_t<0>, Q>));
BOOST_TEST_TRAIT_FALSE((mp_valid<mp_fold_q, mp_list<void, int, int, int>, mp_size_t<0>, Q>));
BOOST_TEST_TRAIT_FALSE((mp_valid<mp_fold_q, mp_list<int, void, int>, mp_size_t<0>, Q>));
BOOST_TEST_TRAIT_FALSE((mp_valid<mp_fold_q, mp_list<int, void, int, int>, mp_size_t<0>, Q>));
BOOST_TEST_TRAIT_FALSE((mp_valid<mp_fold_q, mp_list<int, int, void, int>, mp_size_t<0>, Q>));
#endif
return boost::report_errors();
}