From afd396692041044e9d8bc5c8b80444ede64c6e4b Mon Sep 17 00:00:00 2001 From: Kris Jusiak Date: Sat, 12 Jun 2021 17:42:23 +0000 Subject: [PATCH] :new: Add `mp_quote_expr` to quote with lambda expressions Problem: - There is no easy way to quote metafunction directly with lambda expressions. Solution: - Add mp_quote_expr. Note: - mp_quote_expr requires C++20. --- doc/mp11/utility.adoc | 34 ++++++++++++++ include/boost/mp11/detail/config.hpp | 12 +++++ include/boost/mp11/utility.hpp | 8 ++++ test/Jamfile | 1 + test/mp_quote_expr.cpp | 69 ++++++++++++++++++++++++++++ 5 files changed, 124 insertions(+) create mode 100644 test/mp_quote_expr.cpp diff --git a/doc/mp11/utility.adoc b/doc/mp11/utility.adoc index d5bb6220..a9ad9481 100644 --- a/doc/mp11/utility.adoc +++ b/doc/mp11/utility.adoc @@ -246,6 +246,40 @@ using R1 = mp_transform_q, L1>; // mp_list ``` +## mp_quote_expr + + template + struct mp_quote_expr { + template + using fn = decltype(Expr(std::declval()...)); + }; + +`mp_quote_expr` transforms the template `Expr` into a _quoted metafunction_, a type with a nested template `fn` such that `fn` returns `Expr(std::declval()...)`. + +.Using mp_quote_expr to wrap types depending on whether they have a `value` or not +``` +template struct with_value {}; +template struct without_value {}; + +struct foo { int value{}; }; +struct bar { }; + +using L1 = mp_list; +using R1 = mp_transform_q< + mp_quote_expr<[](T t) { + if constexpr (requires { t.value; }) { + return with_value{}; + } else { + return without_value{}; + } + }>, + L1 + >; + // mp_list, without_value> +``` + +> `mp_quote_trait` requires C++20 support + ## mp_invoke_q template using mp_invoke_q = typename Q::template fn; diff --git a/include/boost/mp11/detail/config.hpp b/include/boost/mp11/detail/config.hpp index 0a9ded50..b6c1f31b 100644 --- a/include/boost/mp11/detail/config.hpp +++ b/include/boost/mp11/detail/config.hpp @@ -113,6 +113,18 @@ # define BOOST_MP11_HAS_FOLD_EXPRESSIONS #endif +// BOOST_MP11_HAS_NONTYPE_TEMPLATE_ARGS + +#if !defined(BOOST_MP11_HAS_NONTYPE_TEMPLATE_ARGS) && defined(__cpp_nontype_template_args) && __cpp_nontype_template_args >= 201911 +# define BOOST_MP11_HAS_NONTYPE_TEMPLATE_ARGS +#endif + +// BOOST_MP11_HAS_NONTYPE_TEMPLATE_PARAMETER_AUTO + +#if !defined(BOOST_MP11_HAS_NONTYPE_TEMPLATE_PARAMETER_AUTO) && defined(__cpp_nontype_template_parameter_auto) && __cpp_nontype_template_parameter_auto >= 201606 +# define BOOST_MP11_HAS_NONTYPE_TEMPLATE_PARAMETER_AUTO +#endif + // BOOST_MP11_HAS_TYPE_PACK_ELEMENT #if defined(__has_builtin) diff --git a/include/boost/mp11/utility.hpp b/include/boost/mp11/utility.hpp index 533009aa..0447dfba 100644 --- a/include/boost/mp11/utility.hpp +++ b/include/boost/mp11/utility.hpp @@ -251,6 +251,14 @@ template struct mp_compose_q template using fn = mp_fold, T, detail::mp_reverse_invoke_q>; }; +#if defined(BOOST_MP11_HAS_NONTYPE_TEMPLATE_ARGS) && defined(BOOST_MP11_HAS_NONTYPE_TEMPLATE_PARAMETER_AUTO) +template +struct mp_quote_expr { + template + using fn = decltype(Expr(std::declval()...)); +}; +#endif + } // namespace mp11 } // namespace boost diff --git a/test/Jamfile b/test/Jamfile index 0a1be298..b660529a 100644 --- a/test/Jamfile +++ b/test/Jamfile @@ -142,6 +142,7 @@ run mp_defer.cpp ; run mp_quote.cpp ; run mp_invoke_q.cpp ; run mp_invoke_q_sf.cpp ; +run mp_quote_expr.cpp ; run mp_quote_trait.cpp ; run mp_cond.cpp ; run mp_cond_sf.cpp ; diff --git a/test/mp_quote_expr.cpp b/test/mp_quote_expr.cpp new file mode 100644 index 00000000..4c30240d --- /dev/null +++ b/test/mp_quote_expr.cpp @@ -0,0 +1,69 @@ + +// Copyright 2021 Kris Jusiak. +// +// 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 +#include +#include +#include + +int main() +{ +#if defined(BOOST_MP11_HAS_NONTYPE_TEMPLATE_ARGS) && defined(BOOST_MP11_HAS_NONTYPE_TEMPLATE_PARAMETER_AUTO) + using boost::mp11::mp_list; + using boost::mp11::mp_transform_q; + using boost::mp11::mp_quote_expr; + + constexpr auto expr = [](auto t) { return t; }; + + { + BOOST_TEST_TRAIT_TRUE((std::is_same< + mp_list<>, + mp_transform_q< + mp_quote_expr, + mp_list<> + > + >)); + } + + { + BOOST_TEST_TRAIT_TRUE((std::is_same< + mp_list, + mp_transform_q< + mp_quote_expr, + mp_list + > + >)); + } + + struct a{}; + struct b{}; + + { + BOOST_TEST_TRAIT_TRUE((std::is_same< + mp_list, + mp_transform_q< + mp_quote_expr, + mp_list + > + >)); + } + + { + constexpr auto to_ptr = [](auto& t) { return &t; }; + + BOOST_TEST_TRAIT_TRUE((std::is_same< + mp_list, + mp_transform_q< + mp_quote_expr, + mp_list + > + >)); + } +#endif + return boost::report_errors(); +}