diff --git a/doc/mp11/changelog.adoc b/doc/mp11/changelog.adoc index 59f3d17..b58f9d9 100644 --- a/doc/mp11/changelog.adoc +++ b/doc/mp11/changelog.adoc @@ -1,5 +1,5 @@ //// -Copyright 2019-2023 Peter Dimov +Copyright 2019-2024 Peter Dimov Distributed under the Boost Software License, Version 1.0. @@ -10,6 +10,10 @@ http://www.boost.org/LICENSE_1_0.txt [#changelog] # Revision History +## Changes in 1.87.0 + +* Added `mp_lambda` + ## Changes in 1.85.0 * Added `mp_sliding_fold`, a generalization of `mp_pairwise_fold` (contributed by Braden Ganetsky) diff --git a/doc/mp11/lambda.adoc b/doc/mp11/lambda.adoc new file mode 100644 index 0000000..bfa9f03 --- /dev/null +++ b/doc/mp11/lambda.adoc @@ -0,0 +1,34 @@ +//// +Copyright 2024 Joaquin M Lopez Munoz + +Distributed under the Boost Software License, Version 1.0. + +See accompanying file LICENSE_1_0.txt or copy at +http://www.boost.org/LICENSE_1_0.txt +//// + +[#lambda] +# Lambda, +:toc: +:toc-title: +:idprefix: + +## mp_lambda + + template using mp_lambda = /*...*/; + +`mp_lambda` is a quoted metafunction whose nested template `fn` +returns a type `V` with the same syntactic definition as `T`, except +that occurrences of placeholders in `T` are replaced by the corresponding +element of `U...`. + +For example, `mp_lambda>::fn` is `std::pair`. + +Replacement does not happen inside those constituent parts of `T` resulting +from the instantiation of a class template with non-type template parameters. + +NOTE: In GCC 4.8, a compiler bug results in `const` and `volatile` qualifiers +being stripped from the returned type `V` (except when they are applied to +function or member function types). + +NOTE: `mp_lambda` is not supported in VS2013 and prior due to compiler limitations. diff --git a/doc/mp11/reference.adoc b/doc/mp11/reference.adoc index d836ce8..ebe52d0 100644 --- a/doc/mp11/reference.adoc +++ b/doc/mp11/reference.adoc @@ -1,5 +1,5 @@ //// -Copyright 2017 Peter Dimov +Copyright 2017-2024 Peter Dimov Distributed under the Boost Software License, Version 1.0. @@ -33,6 +33,8 @@ include::function.adoc[] include::bind.adoc[] +include::lambda.adoc[] + include::integer_sequence.adoc[] include::tuple.adoc[] diff --git a/include/boost/mp11.hpp b/include/boost/mp11.hpp index 5e45939..799a306 100644 --- a/include/boost/mp11.hpp +++ b/include/boost/mp11.hpp @@ -1,7 +1,7 @@ #ifndef BOOST_MP11_HPP_INCLUDED #define BOOST_MP11_HPP_INCLUDED -// Copyright 2015 Peter Dimov. +// Copyright 2015-2024 Peter Dimov. // // Distributed under the Boost Software License, Version 1.0. // @@ -16,6 +16,7 @@ #include #include #include +#include #include #include diff --git a/include/boost/mp11/lambda.hpp b/include/boost/mp11/lambda.hpp new file mode 100644 index 0000000..9f78d55 --- /dev/null +++ b/include/boost/mp11/lambda.hpp @@ -0,0 +1,195 @@ +#ifndef BOOST_MP11_LAMBDA_HPP_INCLUDED +#define BOOST_MP11_LAMBDA_HPP_INCLUDED + +// Copyright 2024 Joaquin M Lopez Munoz. +// +// Distributed under the Boost Software License, Version 1.0. +// +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt + +#include + +#if BOOST_MP11_WORKAROUND(BOOST_MP11_MSVC, <= 1800) +// mp_lambda not supported due to compiler limitations +#else + +#include +#include +#include + +#if defined(_MSC_VER) || defined(__GNUC__) +# pragma push_macro( "I" ) +# undef I +#endif + +namespace boost +{ +namespace mp11 +{ +namespace detail +{ + +template struct lambda_impl; + +} // namespace detail + +// mp_lambda +template using mp_lambda = typename detail::lambda_impl::type; + +namespace detail +{ + +// base case (no placeholder replacement) +template struct lambda_impl +{ + template using make = T; + using type = mp_bind; +}; + +// placeholders (behave directly as mp_bind expressions) +template struct lambda_impl> +{ + using type = mp_arg; +}; + +#define BOOST_MP11_SPECIALIZE_LAMBDA_IMPL(name, compound_type) \ +template using lambda_make_##name = compound_type; \ + \ +template struct lambda_impl \ +{ \ + using type = mp_bind>; \ +}; + +// [basic.type.qualifier] +BOOST_MP11_SPECIALIZE_LAMBDA_IMPL(const, const T) +BOOST_MP11_SPECIALIZE_LAMBDA_IMPL(volatile, volatile T) +BOOST_MP11_SPECIALIZE_LAMBDA_IMPL(const_volatile, const volatile T) + +// [dcl.ptr] +BOOST_MP11_SPECIALIZE_LAMBDA_IMPL(pointer, T*) + +// [dcl.ref] +// GCC < 7 fails with template using make = U&; +template struct lambda_impl +{ + template using make = typename std::add_lvalue_reference::type; + using type = mp_bind>; +}; + +template struct lambda_impl +{ + template using make = typename std::add_rvalue_reference::type; + using type = mp_bind>; +}; + +// [dcl.array] +BOOST_MP11_SPECIALIZE_LAMBDA_IMPL(array, T[]) + +#undef BOOST_MP11_SPECIALIZE_LAMBDA_IMPL + +template struct lambda_impl +{ + template using make = Q[N]; + using type = mp_bind>; +}; + +// [dcl.fct], [dcl.mptr] (member functions) +#define BOOST_MP11_SPECIALIZE_LAMBDA_IMPL_FCT_AND_MFPTR(name, qualifier) \ +template using lambda_make_fct_##name = R(T...) qualifier; \ + \ +template struct lambda_impl \ +{ \ + using type = mp_bind< \ + lambda_make_fct_##name, \ + mp_lambda, mp_lambda...>; \ +}; \ + \ +template using lambda_make_fct_##name##_ellipsis = \ + R(T..., ...) qualifier; \ + \ +template struct lambda_impl \ +{ \ + using type = mp_bind< \ + lambda_make_fct_##name##_ellipsis, \ + mp_lambda, mp_lambda...>; \ +}; \ + \ +template using lambda_make_mfptr_##name = \ + R (C::*)(T...) qualifier; \ + \ +template struct lambda_impl \ +{ \ + using type = mp_bind< \ + lambda_make_mfptr_##name, \ + mp_lambda, mp_lambda, mp_lambda...>; \ +}; \ + \ +template using lambda_make_mfptr_##name##_ellipsis = \ + R (C::*)(T..., ...) qualifier; \ + \ +template struct lambda_impl \ +{ \ + using type = mp_bind< \ + lambda_make_mfptr_##name##_ellipsis, \ + mp_lambda, mp_lambda, mp_lambda...>; \ +}; + +#define BOOST_MP11_EMPTY() + +BOOST_MP11_SPECIALIZE_LAMBDA_IMPL_FCT_AND_MFPTR(no_qualifier, BOOST_MP11_EMPTY()) +BOOST_MP11_SPECIALIZE_LAMBDA_IMPL_FCT_AND_MFPTR(const, const) +BOOST_MP11_SPECIALIZE_LAMBDA_IMPL_FCT_AND_MFPTR(volatile, volatile) +BOOST_MP11_SPECIALIZE_LAMBDA_IMPL_FCT_AND_MFPTR(const_volatile, const volatile) +BOOST_MP11_SPECIALIZE_LAMBDA_IMPL_FCT_AND_MFPTR(ref, &) +BOOST_MP11_SPECIALIZE_LAMBDA_IMPL_FCT_AND_MFPTR(const_ref, const&) +BOOST_MP11_SPECIALIZE_LAMBDA_IMPL_FCT_AND_MFPTR(volatile_ref, volatile&) +BOOST_MP11_SPECIALIZE_LAMBDA_IMPL_FCT_AND_MFPTR(const_volatile_ref, const volatile&) +BOOST_MP11_SPECIALIZE_LAMBDA_IMPL_FCT_AND_MFPTR(rvalue_ref, &&) +BOOST_MP11_SPECIALIZE_LAMBDA_IMPL_FCT_AND_MFPTR(const_rvalue_ref, const&&) +BOOST_MP11_SPECIALIZE_LAMBDA_IMPL_FCT_AND_MFPTR(volatile_rvalue_ref, volatile&&) +BOOST_MP11_SPECIALIZE_LAMBDA_IMPL_FCT_AND_MFPTR(const_volatile_rvalue_ref, const volatile&&) + +#if (defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) || __cplusplus >= 201703L +// P0012R1: exception specification as part of the type system +BOOST_MP11_SPECIALIZE_LAMBDA_IMPL_FCT_AND_MFPTR(noexcept, noexcept) +BOOST_MP11_SPECIALIZE_LAMBDA_IMPL_FCT_AND_MFPTR(const_noexcept, const noexcept) +BOOST_MP11_SPECIALIZE_LAMBDA_IMPL_FCT_AND_MFPTR(volatile_noexcept, volatile noexcept) +BOOST_MP11_SPECIALIZE_LAMBDA_IMPL_FCT_AND_MFPTR(const_volatile_noexcept, const volatile noexcept) +BOOST_MP11_SPECIALIZE_LAMBDA_IMPL_FCT_AND_MFPTR(ref_noexcept, & noexcept) +BOOST_MP11_SPECIALIZE_LAMBDA_IMPL_FCT_AND_MFPTR(const_ref_noexcept, const& noexcept) +BOOST_MP11_SPECIALIZE_LAMBDA_IMPL_FCT_AND_MFPTR(volatile_ref_noexcept, volatile& noexcept) +BOOST_MP11_SPECIALIZE_LAMBDA_IMPL_FCT_AND_MFPTR(const_volatile_ref_noexcept, const volatile& noexcept) +BOOST_MP11_SPECIALIZE_LAMBDA_IMPL_FCT_AND_MFPTR(rvalue_ref_noexcept, && noexcept) +BOOST_MP11_SPECIALIZE_LAMBDA_IMPL_FCT_AND_MFPTR(const_rvalue_ref_noexcept, const&& noexcept) +BOOST_MP11_SPECIALIZE_LAMBDA_IMPL_FCT_AND_MFPTR(volatile_rvalue_ref_noexcept, volatile&& noexcept) +BOOST_MP11_SPECIALIZE_LAMBDA_IMPL_FCT_AND_MFPTR(const_volatile_rvalue_ref_noexcept, const volatile&& noexcept) +#endif // P0012R1 + +#undef BOOST_MP11_EMPTY +#undef BOOST_MP11_SPECIALIZE_LAMBDA_IMPL_FCT_AND_MFPTR + +// [dcl.mptr] (data members) +template struct lambda_impl +{ + template using make = U (D::*); + using type = mp_bind, mp_lambda>; +}; + +// template class instantiation +template