From 29a771aa4eacc065af6bf133364621360cf56223 Mon Sep 17 00:00:00 2001 From: Peter Dimov Date: Tue, 23 May 2017 20:24:37 +0300 Subject: [PATCH 01/14] Move integer_sequence and tuple_for_each into mp11 --- doc/html/mp11.html | 26 +++---- doc/mp11.qbk | 2 +- doc/mp11/examples.qbk | 3 +- doc/mp11/integer_sequence.qbk | 4 +- doc/mp11/tuple_for_each.qbk | 4 +- include/boost/mp11.hpp | 2 + include/boost/mp11/algorithm.hpp | 2 +- include/boost/{ => mp11}/integer_sequence.hpp | 16 ++++- include/boost/{ => mp11}/tuple_for_each.hpp | 22 ++++-- test/integer_sequence.cpp | 68 ++++++++++--------- test/tuple_for_each.cpp | 26 +++---- test/tuple_for_each_cx.cpp | 6 +- 12 files changed, 99 insertions(+), 82 deletions(-) rename include/boost/{ => mp11}/integer_sequence.hpp (84%) rename include/boost/{ => mp11}/tuple_for_each.hpp (57%) diff --git a/doc/html/mp11.html b/doc/html/mp11.html index 1e3acf2..d3e10e3 100644 --- a/doc/html/mp11.html +++ b/doc/html/mp11.html @@ -187,7 +187,7 @@
mp_bind_back_q<Q, T...>
Integer Sequences, - <boost/integer_sequence.hpp>
+ <boost/mp11/integer_sequence.hpp>
integer_sequence<T, I...>
make_integer_sequence<T, N>
@@ -196,7 +196,7 @@
index_sequence_for<T...>
A "for each" - algorithm for tuple-like types, <boost/tuple_for_each.hpp>
+ algorithm for tuple-like types, <boost/mp11/tuple_for_each.hpp>
tuple_for_each
@@ -341,7 +341,6 @@ worst of all, boring. This is how we can leverage Mp11 to automate the task:

#include <boost/mp11.hpp>
-#include <boost/tuple_for_each.hpp>
 #include <boost/core/demangle.hpp>
 #include <type_traits>
 #include <iostream>
@@ -369,7 +368,7 @@
 int main()
 {
     using L = std::tuple<char, short, int, unsigned, long, unsigned long>;
-    boost::tuple_for_each( mp_product<mp_list, L, L>(), [](auto&& x){ test_result(x); } );
+    tuple_for_each( mp_product<mp_list, L, L>(), [](auto&& x){ test_result(x); } );
 }
 

@@ -871,8 +870,7 @@ Reference

- The contents of the library are in namespace boost::mp11, unless - specified otherwise. + The contents of the library are in namespace boost::mp11.

@@ -2332,12 +2330,9 @@

-

- The contents of this header are defined in namespace boost. -

integer_sequence<T, I...> @@ -2401,12 +2396,9 @@

-

- The contents of this header are defined in namespace boost. -

tuple_for_each @@ -2429,7 +2421,7 @@

- +

Last revised: May 22, 2017 at 13:46:31 GMT

Last revised: May 23, 2017 at 17:21:43 GMT


diff --git a/doc/mp11.qbk b/doc/mp11.qbk index db40f52..51e6b83 100644 --- a/doc/mp11.qbk +++ b/doc/mp11.qbk @@ -29,7 +29,7 @@ [section Reference] -The contents of the library are in namespace `boost::mp11`, unless specified otherwise. +The contents of the library are in namespace `boost::mp11`. [include mp11/integral.qbk] [include mp11/list.qbk] diff --git a/doc/mp11/examples.qbk b/doc/mp11/examples.qbk index 93aad48..a54a458 100644 --- a/doc/mp11/examples.qbk +++ b/doc/mp11/examples.qbk @@ -42,7 +42,6 @@ Writing all those type combinations by hand is unwieldy, error prone, and worst how we can leverage Mp11 to automate the task: #include - #include #include #include #include @@ -70,7 +69,7 @@ how we can leverage Mp11 to automate the task: int main() { using L = std::tuple; - boost::tuple_for_each( mp_product(), [](auto&& x){ test_result(x); } ); + tuple_for_each( mp_product(), [](auto&& x){ test_result(x); } ); } How does it work? diff --git a/doc/mp11/integer_sequence.qbk b/doc/mp11/integer_sequence.qbk index f0604b6..199634a 100644 --- a/doc/mp11/integer_sequence.qbk +++ b/doc/mp11/integer_sequence.qbk @@ -6,9 +6,7 @@ / http://www.boost.org/LICENSE_1_0.txt) /] -[section:integer_sequence Integer Sequences, ``] - -The contents of this header are defined in namespace `boost`. +[section:integer_sequence Integer Sequences, ``] [section `integer_sequence`] template struct integer_sequence diff --git a/doc/mp11/tuple_for_each.qbk b/doc/mp11/tuple_for_each.qbk index 2b06fcd..4eb6b9e 100644 --- a/doc/mp11/tuple_for_each.qbk +++ b/doc/mp11/tuple_for_each.qbk @@ -6,9 +6,7 @@ / http://www.boost.org/LICENSE_1_0.txt) /] -[section:tuple_for_each A "for each" algorithm for tuple-like types, ``] - -The contents of this header are defined in namespace `boost`. +[section:tuple_for_each A "for each" algorithm for tuple-like types, ``] [section `tuple_for_each`] template constexpr F tuple_for_each(Tp&& tp, F&& f); diff --git a/include/boost/mp11.hpp b/include/boost/mp11.hpp index 4241337..05a51ca 100644 --- a/include/boost/mp11.hpp +++ b/include/boost/mp11.hpp @@ -16,5 +16,7 @@ #include #include #include +#include +#include #endif // #ifndef BOOST_MP11_HPP_INCLUDED diff --git a/include/boost/mp11/algorithm.hpp b/include/boost/mp11/algorithm.hpp index 1762502..9f0a6f7 100644 --- a/include/boost/mp11/algorithm.hpp +++ b/include/boost/mp11/algorithm.hpp @@ -17,7 +17,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/include/boost/integer_sequence.hpp b/include/boost/mp11/integer_sequence.hpp similarity index 84% rename from include/boost/integer_sequence.hpp rename to include/boost/mp11/integer_sequence.hpp index 9ddfc99..08e3120 100644 --- a/include/boost/integer_sequence.hpp +++ b/include/boost/mp11/integer_sequence.hpp @@ -1,10 +1,19 @@ -#ifndef BOOST_INTEGER_SEQUENCE_HPP_INCLUDED -#define BOOST_INTEGER_SEQUENCE_HPP_INCLUDED +#ifndef BOOST_MP11_INTEGER_SEQUENCE_HPP_INCLUDED +#define BOOST_MP11_INTEGER_SEQUENCE_HPP_INCLUDED + +// Copyright 2015, 2017 Peter Dimov. +// +// 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 namespace boost { +namespace mp11 +{ // integer_sequence template struct integer_sequence @@ -82,6 +91,7 @@ template using make_index_sequence = make_integer_sequence using index_sequence_for = make_integer_sequence; +} // namespace mp11 } // namespace boost -#endif // #ifndef BOOST_INTEGER_SEQUENCE_HPP_INCLUDED +#endif // #ifndef BOOST_MP11_INTEGER_SEQUENCE_HPP_INCLUDED diff --git a/include/boost/tuple_for_each.hpp b/include/boost/mp11/tuple_for_each.hpp similarity index 57% rename from include/boost/tuple_for_each.hpp rename to include/boost/mp11/tuple_for_each.hpp index 8e3d766..a58098e 100644 --- a/include/boost/tuple_for_each.hpp +++ b/include/boost/mp11/tuple_for_each.hpp @@ -1,7 +1,14 @@ -#ifndef BOOST_TUPLE_FOR_EACH_HPP_INCLUDED -#define BOOST_TUPLE_FOR_EACH_HPP_INCLUDED +#ifndef BOOST_MP11_TUPLE_FOR_EACH_HPP_INCLUDED +#define BOOST_MP11_TUPLE_FOR_EACH_HPP_INCLUDED -#include +// Copyright 2015, 2017 Peter Dimov. +// +// 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 @@ -11,11 +18,13 @@ namespace boost { +namespace mp11 +{ namespace detail { -template BOOST_CONSTEXPR F tuple_for_each_impl( Tp && tp, boost::integer_sequence, F && f ) +template BOOST_CONSTEXPR F tuple_for_each_impl( Tp && tp, integer_sequence, F && f ) { using A = int[sizeof...(J)]; return (void)A{ ((void)f(std::get(std::forward(tp))), 0)... }, std::forward(f); @@ -23,7 +32,7 @@ template BOOST_CONSTEXPR F tuple_for_each_i #if BOOST_WORKAROUND( BOOST_MSVC, <= 1800 ) -template BOOST_CONSTEXPR F tuple_for_each_impl( Tp && tp, boost::integer_sequence, F && f ) +template BOOST_CONSTEXPR F tuple_for_each_impl( Tp && tp, integer_sequence, F && f ) { return std::forward(f); } @@ -34,10 +43,11 @@ template BOOST_CONSTEXPR F tuple_for_each_impl( Tp && tp, boo template BOOST_CONSTEXPR F tuple_for_each( Tp && tp, F && f ) { - using seq = boost::make_index_sequence::type>::value>; + using seq = make_index_sequence::type>::value>; return detail::tuple_for_each_impl( std::forward(tp), seq(), std::forward(f) ); } +} // namespace mp11 } // namespace boost #endif // #ifndef BOOST_TUPLE_FOR_EACH_HPP_INCLUDED diff --git a/test/integer_sequence.cpp b/test/integer_sequence.cpp index 190b985..bc489ab 100644 --- a/test/integer_sequence.cpp +++ b/test/integer_sequence.cpp @@ -7,47 +7,53 @@ // http://www.boost.org/LICENSE_1_0.txt -#include +#include #include #include int main() { - BOOST_TEST_TRAIT_TRUE((std::is_same, boost::integer_sequence>)); - BOOST_TEST_TRAIT_TRUE((std::is_same, boost::integer_sequence>)); - BOOST_TEST_TRAIT_TRUE((std::is_same, boost::integer_sequence>)); - BOOST_TEST_TRAIT_TRUE((std::is_same, boost::integer_sequence>)); - BOOST_TEST_TRAIT_TRUE((std::is_same, boost::integer_sequence>)); + using boost::mp11::integer_sequence; + using boost::mp11::make_integer_sequence; + using boost::mp11::index_sequence; + using boost::mp11::make_index_sequence; + using boost::mp11::index_sequence_for; - BOOST_TEST_TRAIT_TRUE((std::is_same, boost::integer_sequence>)); - BOOST_TEST_TRAIT_TRUE((std::is_same, boost::integer_sequence>)); - BOOST_TEST_TRAIT_TRUE((std::is_same, boost::integer_sequence>)); - BOOST_TEST_TRAIT_TRUE((std::is_same, boost::integer_sequence>)); - BOOST_TEST_TRAIT_TRUE((std::is_same, boost::integer_sequence>)); + BOOST_TEST_TRAIT_TRUE((std::is_same, integer_sequence>)); + BOOST_TEST_TRAIT_TRUE((std::is_same, integer_sequence>)); + BOOST_TEST_TRAIT_TRUE((std::is_same, integer_sequence>)); + BOOST_TEST_TRAIT_TRUE((std::is_same, integer_sequence>)); + BOOST_TEST_TRAIT_TRUE((std::is_same, integer_sequence>)); - BOOST_TEST_TRAIT_TRUE((std::is_same, boost::integer_sequence>)); - BOOST_TEST_TRAIT_TRUE((std::is_same, boost::integer_sequence>)); - BOOST_TEST_TRAIT_TRUE((std::is_same, boost::integer_sequence>)); - BOOST_TEST_TRAIT_TRUE((std::is_same, boost::integer_sequence>)); - BOOST_TEST_TRAIT_TRUE((std::is_same, boost::integer_sequence>)); + BOOST_TEST_TRAIT_TRUE((std::is_same, integer_sequence>)); + BOOST_TEST_TRAIT_TRUE((std::is_same, integer_sequence>)); + BOOST_TEST_TRAIT_TRUE((std::is_same, integer_sequence>)); + BOOST_TEST_TRAIT_TRUE((std::is_same, integer_sequence>)); + BOOST_TEST_TRAIT_TRUE((std::is_same, integer_sequence>)); - BOOST_TEST_TRAIT_TRUE((std::is_same, boost::integer_sequence>)); - BOOST_TEST_TRAIT_TRUE((std::is_same, boost::integer_sequence>)); - BOOST_TEST_TRAIT_TRUE((std::is_same, boost::integer_sequence>)); - BOOST_TEST_TRAIT_TRUE((std::is_same, boost::integer_sequence>)); - BOOST_TEST_TRAIT_TRUE((std::is_same, boost::integer_sequence>)); + BOOST_TEST_TRAIT_TRUE((std::is_same, integer_sequence>)); + BOOST_TEST_TRAIT_TRUE((std::is_same, integer_sequence>)); + BOOST_TEST_TRAIT_TRUE((std::is_same, integer_sequence>)); + BOOST_TEST_TRAIT_TRUE((std::is_same, integer_sequence>)); + BOOST_TEST_TRAIT_TRUE((std::is_same, integer_sequence>)); - BOOST_TEST_TRAIT_TRUE((std::is_same, boost::index_sequence<>>)); - BOOST_TEST_TRAIT_TRUE((std::is_same, boost::index_sequence<0>>)); - BOOST_TEST_TRAIT_TRUE((std::is_same, boost::index_sequence<0, 1>>)); - BOOST_TEST_TRAIT_TRUE((std::is_same, boost::index_sequence<0, 1, 2>>)); - BOOST_TEST_TRAIT_TRUE((std::is_same, boost::index_sequence<0, 1, 2, 3>>)); + BOOST_TEST_TRAIT_TRUE((std::is_same, integer_sequence>)); + BOOST_TEST_TRAIT_TRUE((std::is_same, integer_sequence>)); + BOOST_TEST_TRAIT_TRUE((std::is_same, integer_sequence>)); + BOOST_TEST_TRAIT_TRUE((std::is_same, integer_sequence>)); + BOOST_TEST_TRAIT_TRUE((std::is_same, integer_sequence>)); - BOOST_TEST_TRAIT_TRUE((std::is_same, boost::index_sequence<>>)); - BOOST_TEST_TRAIT_TRUE((std::is_same, boost::index_sequence<0>>)); - BOOST_TEST_TRAIT_TRUE((std::is_same, boost::index_sequence<0, 1>>)); - BOOST_TEST_TRAIT_TRUE((std::is_same, boost::index_sequence<0, 1, 2>>)); - BOOST_TEST_TRAIT_TRUE((std::is_same, boost::index_sequence<0, 1, 2, 3>>)); + BOOST_TEST_TRAIT_TRUE((std::is_same, index_sequence<>>)); + BOOST_TEST_TRAIT_TRUE((std::is_same, index_sequence<0>>)); + BOOST_TEST_TRAIT_TRUE((std::is_same, index_sequence<0, 1>>)); + BOOST_TEST_TRAIT_TRUE((std::is_same, index_sequence<0, 1, 2>>)); + BOOST_TEST_TRAIT_TRUE((std::is_same, index_sequence<0, 1, 2, 3>>)); + + BOOST_TEST_TRAIT_TRUE((std::is_same, index_sequence<>>)); + BOOST_TEST_TRAIT_TRUE((std::is_same, index_sequence<0>>)); + BOOST_TEST_TRAIT_TRUE((std::is_same, index_sequence<0, 1>>)); + BOOST_TEST_TRAIT_TRUE((std::is_same, index_sequence<0, 1, 2>>)); + BOOST_TEST_TRAIT_TRUE((std::is_same, index_sequence<0, 1, 2, 3>>)); return boost::report_errors(); } diff --git a/test/tuple_for_each.cpp b/test/tuple_for_each.cpp index e8880dd..449fd15 100644 --- a/test/tuple_for_each.cpp +++ b/test/tuple_for_each.cpp @@ -7,7 +7,7 @@ // http://www.boost.org/LICENSE_1_0.txt -#include +#include #include #include #include @@ -16,13 +16,15 @@ int main() { + using boost::mp11::tuple_for_each; + { std::tuple tp{ 1, 2, 3 }; { int s = 0; - boost::tuple_for_each( tp, [&]( int x ){ s = s * 10 + x; } ); + tuple_for_each( tp, [&]( int x ){ s = s * 10 + x; } ); BOOST_TEST_EQ( s, 123 ); } @@ -30,7 +32,7 @@ int main() { int s = 0; - boost::tuple_for_each( std::move(tp), [&]( int x ){ s = s * 10 + x; } ); + tuple_for_each( std::move(tp), [&]( int x ){ s = s * 10 + x; } ); BOOST_TEST_EQ( s, 123 ); } @@ -44,7 +46,7 @@ int main() int s = 0; - boost::tuple_for_each( std::move(tp), [&]( std::unique_ptr p ){ s = s * 10 + *p; } ); + tuple_for_each( std::move(tp), [&]( std::unique_ptr p ){ s = s * 10 + *p; } ); BOOST_TEST_EQ( s, 123 ); } @@ -57,7 +59,7 @@ int main() { int s = 0; - boost::tuple_for_each( tp, [&]( int x ){ s = s * 10 + x; } ); + tuple_for_each( tp, [&]( int x ){ s = s * 10 + x; } ); BOOST_TEST_EQ( s, 12 ); } @@ -65,7 +67,7 @@ int main() { int s = 0; - boost::tuple_for_each( std::move(tp), [&]( int x ){ s = s * 10 + x; } ); + tuple_for_each( std::move(tp), [&]( int x ){ s = s * 10 + x; } ); BOOST_TEST_EQ( s, 12 ); } @@ -77,7 +79,7 @@ int main() { int s = 0; - boost::tuple_for_each( tp, [&]( int x ){ s = s * 10 + x; } ); + tuple_for_each( tp, [&]( int x ){ s = s * 10 + x; } ); BOOST_TEST_EQ( s, 123 ); } @@ -85,7 +87,7 @@ int main() { int s = 0; - boost::tuple_for_each( std::move(tp), [&]( int x ){ s = s * 10 + x; } ); + tuple_for_each( std::move(tp), [&]( int x ){ s = s * 10 + x; } ); BOOST_TEST_EQ( s, 123 ); } @@ -94,15 +96,15 @@ int main() { std::tuple<> tp; - BOOST_TEST_EQ( boost::tuple_for_each( tp, 11 ), 11 ); - BOOST_TEST_EQ( boost::tuple_for_each( std::move( tp ), 12 ), 12 ); + BOOST_TEST_EQ( tuple_for_each( tp, 11 ), 11 ); + BOOST_TEST_EQ( tuple_for_each( std::move( tp ), 12 ), 12 ); } { std::array tp; - BOOST_TEST_EQ( boost::tuple_for_each( tp, 11 ), 11 ); - BOOST_TEST_EQ( boost::tuple_for_each( std::move( tp ), 12 ), 12 ); + BOOST_TEST_EQ( tuple_for_each( tp, 11 ), 11 ); + BOOST_TEST_EQ( tuple_for_each( std::move( tp ), 12 ), 12 ); } return boost::report_errors(); diff --git a/test/tuple_for_each_cx.cpp b/test/tuple_for_each_cx.cpp index 305d737..730f6d2 100644 --- a/test/tuple_for_each_cx.cpp +++ b/test/tuple_for_each_cx.cpp @@ -6,7 +6,7 @@ // See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt -#include +#include #include // Technically std::tuple isn't constexpr enabled in C++11, but it works with libstdc++ @@ -33,7 +33,7 @@ int main() { { constexpr std::tuple tp{ 1, 2, 3 }; - constexpr auto r = boost::tuple_for_each( tp, assert_is_integral() ); + constexpr auto r = boost::mp11::tuple_for_each( tp, assert_is_integral() ); (void)r; } @@ -42,7 +42,7 @@ int main() { constexpr std::tuple<> tp; - constexpr auto r = boost::tuple_for_each( tp, 11 ); + constexpr auto r = boost::mp11::tuple_for_each( tp, 11 ); static_assert( r == 11, "r == 11" ); } From dc0faed438adff6dca6b68d8ce5903d993279bc1 Mon Sep 17 00:00:00 2001 From: Peter Dimov Date: Tue, 23 May 2017 20:39:57 +0300 Subject: [PATCH 02/14] Remove unnecessary C++14 use from examples --- doc/html/mp11.html | 57 ++++++++++++++++++++++++++++++------------- doc/mp11/examples.qbk | 49 +++++++++++++++++++++++++++---------- 2 files changed, 76 insertions(+), 30 deletions(-) diff --git a/doc/html/mp11.html b/doc/html/mp11.html index d3e10e3..3cdc9d4 100644 --- a/doc/html/mp11.html +++ b/doc/html/mp11.html @@ -304,8 +304,8 @@ Let's suppose that we have written a metafunction result<T, U>:

-
template<class T> using promote = std::common_type_t<T, int>;
-template<class T, class U> using result = std::common_type_t<promote<T>, promote<U>>;
+
template<class T> using promote = typename std::common_type<T, int>::type;
+template<class T, class U> using result = typename std::common_type<promote<T>, promote<U>>::type;
 

that ought to represent the result of an arithmetic operation on the integer @@ -353,8 +353,8 @@ return boost::core::demangle( typeid(T).name() ); } -template<class T> using promote = std::common_type_t<T, int>; -template<class T, class U> using result = std::common_type_t<promote<T>, promote<U>>; +template<class T> using promote = typename std::common_type<T, int>::type; +template<class T, class U> using result = typename std::common_type<promote<T>, promote<U>>::type; template<class T1, class T2> void test_result( mp_list<T1, T2> const& ) { @@ -396,11 +396,33 @@

We then default-construct this tuple and pass it to tuple_for_each. tuple_for_each(tp, f) calls f - for every tuple element; we use a (C++14) lambda that calls test_result. (In pure C++11, we'd need - to make test_result a function - object with a templated operator() and pass that to tuple_for_each - directly.) + for every tuple element; we use a (C++14) lambda that calls test_result.

+

+ In pure C++11, we can't use a lambda with an auto&& parameter, so we'll have to make + test_result a function object + with a templated operator() + and pass that to tuple_for_each + directly: +

+
struct test_result
+{
+    template<class T1, class T2> void operator()( mp_list<T1, T2> const& ) const
+    {
+        using T3 = decltype( T1() + T2() );
+        using T4 = result<T1, T2>;
+
+        std::cout << ( std::is_same<T3, T4>::value? "[PASS] ": "[FAIL] " )
+            << name<T1>() << " + " << name<T2>() << " -> " << name<T3>() << ", result: " << name<T4>() << std::endl;
+    }
+};
+
+int main()
+{
+    using L = std::tuple<char, short, int, unsigned, long, unsigned long>;
+    tuple_for_each( mp_product<mp_list, L, L>(), test_result() );
+}
+

@@ -419,7 +441,9 @@ arguments. For that, we need a metafunction that applies std::common_type to each pair of elements and gathers the results into a tuple:

-
template<class Tp1, class Tp2> using common_tuple = mp_transform<std::common_type_t, Tp1, Tp2>;
+
template<class... T> using common_type_t = typename std::common_type<T...>::type; // standard in C++14
+
+template<class Tp1, class Tp2> using common_tuple = mp_transform<common_type_t, Tp1, Tp2>;
 

then specialize common_type @@ -463,16 +487,15 @@ E2, E3> and expected<T2, E1, E4, E5> - is expected<std::common_type_t<T1, T2>, - E1, E2, E3, E4, - E5>. - That is, the possible return values are combined into their common type, - and we take the union of the set of error types. + is expected<common_type_t<T1, T2>, E1, E2, + E3, E4, E5>. That is, the possible return values + are combined into their common type, and we take the union of the set of + error types.

Therefore,

-
template<class T1, class E1, class T2, class E2> using common_expected = mp_rename<mp_push_front<mp_unique<mp_append<E1, E2>>, std::common_type_t<T1, T2>>, expected>;
+
template<class T1, class E1, class T2, class E2> using common_expected = mp_rename<mp_push_front<mp_unique<mp_append<E1, E2>>, common_type_t<T1, T2>>, expected>;
 
 namespace std
 {
@@ -491,7 +514,7 @@
         This makes our job easier. mp_unique<mp_append<E1, E2>>
         gives us the concatenation of E1
         and E2 with the duplicates
-        removed; we then add std::common_type_t<T1, T2>
+        removed; we then add common_type_t<T1, T2>
         to the front via mp_push_front;
         and finally, we mp_rename
         the resultant mp_list to
@@ -2421,7 +2444,7 @@
 

- +

Last revised: May 23, 2017 at 17:21:43 GMT

Last revised: May 23, 2017 at 17:37:57 GMT


diff --git a/doc/mp11/examples.qbk b/doc/mp11/examples.qbk index a54a458..fe315a1 100644 --- a/doc/mp11/examples.qbk +++ b/doc/mp11/examples.qbk @@ -12,8 +12,8 @@ Let's suppose that we have written a metafunction `result`: - template using promote = std::common_type_t; - template using result = std::common_type_t, promote>; + template using promote = typename std::common_type::type; + template using result = typename std::common_type, promote>::type; that ought to represent the result of an arithmetic operation on the integer types `T` and `U`, for example `t + u`. We want to test whether `result` gives correct results for various combinations @@ -54,8 +54,8 @@ how we can leverage Mp11 to automate the task: return boost::core::demangle( typeid(T).name() ); } - template using promote = std::common_type_t; - template using result = std::common_type_t, promote>; + template using promote = typename std::common_type::type; + template using result = typename std::common_type, promote>::type; template void test_result( mp_list const& ) { @@ -82,8 +82,29 @@ In our case, both lists are the same `std::tuple`, and `F` is `mp_list`, so `mp_ `std::tuple, mp_list, mp_list, ..., mp_list, mp_list>`. We then default-construct this tuple and pass it to `tuple_for_each`. `tuple_for_each(tp, f)` calls `f` for every -tuple element; we use a (C++14) lambda that calls `test_result`. (In pure C++11, we'd need to make `test_result` a -function object with a templated `operator()` and pass that to `tuple_for_each` directly.) +tuple element; we use a (C++14) lambda that calls `test_result`. + +In pure C++11, we can't use a lambda with an `auto&&` parameter, so we'll have to make `test_result` a function object with +a templated `operator()` and pass that to `tuple_for_each` directly: + + struct test_result + { + template void operator()( mp_list const& ) const + { + using T3 = decltype( T1() + T2() ); + using T4 = result; + + std::cout << ( std::is_same::value? "[PASS] ": "[FAIL] " ) + << name() << " + " << name() << " -> " << name() << ", result: " << name() << std::endl; + } + }; + + int main() + { + using L = std::tuple; + tuple_for_each( mp_product(), test_result() ); + } + [endsect] [section Writing `common_type` specializations] @@ -95,7 +116,9 @@ operator) is unsuitable. Let's write a `common_type` specialization for two `std::tuple` arguments. For that, we need a metafunction that applies `std::common_type` to each pair of elements and gathers the results into a tuple: - template using common_tuple = mp_transform; + template using common_type_t = typename std::common_type::type; // standard in C++14 + + template using common_tuple = mp_transform; then specialize `common_type` to use it: @@ -119,12 +142,12 @@ and `common_type_t`, which is defined as `typename common_type<...>::type`, will As another example, consider the hypothetical type `expected` that represents either a successful return with a value of `T`, or an unsucessful return with an error code of some type in the list `E...`. The common type of `expected` and -`expected` is `expected, E1, E2, E3, E4, E5>`. That is, the possible return values are +`expected` is `expected, E1, E2, E3, E4, E5>`. That is, the possible return values are combined into their common type, and we take the union of the set of error types. Therefore, - template using common_expected = mp_rename>, std::common_type_t>, expected>; + template using common_expected = mp_rename>, common_type_t>, expected>; namespace std { @@ -137,7 +160,7 @@ Therefore, Here we've taken a different tack; instead of passing the `expected` types to `common_expected`, we're passing the `T` types and lists of the `E` types. This makes our job easier. `mp_unique>` gives us the concatenation of `E1` and `E2` with the duplicates -removed; we then add `std::common_type_t` to the front via `mp_push_front`; and finally, we `mp_rename` the resultant `mp_list` +removed; we then add `common_type_t` to the front via `mp_push_front`; and finally, we `mp_rename` the resultant `mp_list` to `expected`. [endsect] @@ -191,10 +214,10 @@ trying to concatenate tuples containing move-only elements such as `unique_ptr` Trying to concatenate `const` tuples fails: - std::tuple const t1; - std::tuple const t2; + std::tuple const t1; + std::tuple const t2; - auto result = ::tuple_cat( t1, t2 ); + auto result = ::tuple_cat( t1, t2 ); And finally, the standard `tuple_cat` is specified to work on arbitrary tuple-like types (that is, all types that support `tuple_size`, `tuple_element`, and `get`), while our implementation only works with `tuple` and From 07cac40f3d0e7590dda513144e9211877de04622 Mon Sep 17 00:00:00 2001 From: Peter Dimov Date: Tue, 23 May 2017 23:25:30 +0300 Subject: [PATCH 03/14] Change mp_and/mp_or to a SFINAE-based implementation --- doc/html/mp11.html | 26 ++++++++----- doc/mp11/function.qbk | 12 +++--- include/boost/mp11/function.hpp | 68 +++++++++++++++++++++++++++++---- test/mp_and.cpp | 28 +++++++------- test/mp_or.cpp | 42 ++++++++++---------- 5 files changed, 118 insertions(+), 58 deletions(-) diff --git a/doc/html/mp11.html b/doc/html/mp11.html index 3cdc9d4..d671040 100644 --- a/doc/html/mp11.html +++ b/doc/html/mp11.html @@ -2164,12 +2164,15 @@

mp_and<T...> - is an alias for the first type U + is an alias for mp_false + if there exists a type U in T... for which mp_to_bool<U> - is mp_false. If no such - type exists, the last one is returned. mp_and<> is mp_true. - Similar to std::conjunction in C++17. + is mp_false. mp_to_bool<U> + is not evaluated for types after U. + If no such type exists, mp_and<T...> is an alias for mp_true. + (mp_and<> + is mp_true.)

@@ -2189,7 +2192,7 @@ is an error because void does not have a nested value. The upside is that mp_all - is faster. + is faster on legacy compilers.

@@ -2200,12 +2203,15 @@

mp_or<T...> - is an alias for the first type U + is an alias for mp_true + if there exists a type U in T... for which mp_to_bool<U> - is mp_true. If no such - type exists, the last one is returned. mp_or<> is mp_false. - Similar to std::disjunction in C++17. + is mp_true. mp_to_bool<U> + is not evaluated for types after U. + If no such type exists, mp_or<T...> is an alias for mp_false. + (mp_or<> + is mp_false.)

@@ -2444,7 +2450,7 @@
- +

Last revised: May 23, 2017 at 17:37:57 GMT

Last revised: May 23, 2017 at 20:23:39 GMT


diff --git a/doc/mp11/function.qbk b/doc/mp11/function.qbk index 0ccdc49..fca535c 100644 --- a/doc/mp11/function.qbk +++ b/doc/mp11/function.qbk @@ -11,8 +11,9 @@ [section `mp_and`] template using mp_and = /*...*/; -`mp_and` is an alias for the first type `U` in `T...` for which `mp_to_bool` is `mp_false`. -If no such type exists, the last one is returned. `mp_and<>` is `mp_true`. Similar to `std::conjunction` in C++17. +`mp_and` is an alias for `mp_false` if there exists a type `U` in `T...` for which `mp_to_bool` is `mp_false`. +`mp_to_bool` is not evaluated for types after `U`. If no such type exists, `mp_and` is an alias for `mp_true`. +(`mp_and<>` is `mp_true`.) [endsect] [section `mp_all`] @@ -20,14 +21,15 @@ If no such type exists, the last one is returned. `mp_and<>` is `mp_true`. Simil `mp_all` is `mp_true` if `mp_to_bool` is `mp_true` for all types `U` in `T...`, `mp_false` otherwise. Same as `mp_and`, but does not perform short-circuit evaluation. `mp_and` is `mp_false`, but `mp_all` -is an error because `void` does not have a nested `value`. The upside is that `mp_all` is faster. +is an error because `void` does not have a nested `value`. The upside is that `mp_all` is faster on legacy compilers. [endsect] [section `mp_or`] template using mp_or = /*...*/; -`mp_or` is an alias for the first type `U` in `T...` for which `mp_to_bool` is `mp_true`. -If no such type exists, the last one is returned. `mp_or<>` is `mp_false`. Similar to `std::disjunction` in C++17. +`mp_or` is an alias for `mp_true` if there exists a type `U` in `T...` for which `mp_to_bool` is `mp_true`. +`mp_to_bool` is not evaluated for types after `U`. If no such type exists, `mp_or` is an alias for `mp_false`. +(`mp_or<>` is `mp_false`.) [endsect] [section `mp_any`] diff --git a/include/boost/mp11/function.hpp b/include/boost/mp11/function.hpp index 571a24b..04d9dae 100644 --- a/include/boost/mp11/function.hpp +++ b/include/boost/mp11/function.hpp @@ -19,10 +19,10 @@ namespace boost namespace mp11 { -// mp_all -template using mp_all = mp_bool< mp_count_if< mp_list, mp_to_bool >::value == sizeof...(T) >; +// mp_and, mp_all + +#if BOOST_WORKAROUND( BOOST_MSVC, < 1900 ) -// mp_and namespace detail { @@ -30,7 +30,7 @@ template struct mp_and_impl; } // namespace detail -template using mp_and = typename detail::mp_and_impl::type; +template using mp_and = mp_to_bool< typename detail::mp_and_impl::type >; namespace detail { @@ -52,10 +52,36 @@ template struct mp_and_impl } // namespace detail -// mp_any -template using mp_any = mp_bool< mp_count_if< mp_list, mp_to_bool >::value != 0 >; +template using mp_all = mp_bool< mp_count_if< mp_list, mp_to_bool >::value == sizeof...(T) >; + +#else + +namespace detail +{ + +template struct mp_and_impl +{ + using type = mp_false; +}; + +void mp_and_impl_f(...); + +template struct mp_and_impl< mp_list, decltype( mp_and_impl_f( mp_if()... ) ) > +{ + using type = mp_true; +}; + +} // namespace detail + +template using mp_and = typename detail::mp_and_impl>::type; +template using mp_all = typename detail::mp_and_impl>::type; + +#endif + +// mp_or, mp_any + +#if BOOST_WORKAROUND( BOOST_MSVC, < 1900 ) -// mp_or namespace detail { @@ -63,7 +89,7 @@ template struct mp_or_impl; } // namespace detail -template using mp_or = typename detail::mp_or_impl::type; +template using mp_or = mp_to_bool< typename detail::mp_or_impl::type >; namespace detail { @@ -85,6 +111,32 @@ template struct mp_or_impl } // namespace detail +template using mp_any = mp_bool< mp_count_if< mp_list, mp_to_bool >::value != 0 >; + +#else + +namespace detail +{ + +template struct mp_or_impl +{ + using type = mp_true; +}; + +void mp_and_impl_f(...); + +template struct mp_or_impl< mp_list, decltype( mp_and_impl_f( mp_if, int>()... ) ) > +{ + using type = mp_false; +}; + +} // namespace detail + +template using mp_or = typename detail::mp_or_impl>::type; +template using mp_any = typename detail::mp_or_impl>::type; + +#endif + // mp_same namespace detail { diff --git a/test/mp_and.cpp b/test/mp_and.cpp index 0d3c00a..93da74a 100644 --- a/test/mp_and.cpp +++ b/test/mp_and.cpp @@ -25,23 +25,23 @@ int main() BOOST_TEST_TRAIT_TRUE((std::is_same, mp_true>)); BOOST_TEST_TRAIT_TRUE((std::is_same, mp_false>)); - BOOST_TEST_TRAIT_TRUE((std::is_same>, mp_int<-7>>)); - BOOST_TEST_TRAIT_TRUE((std::is_same>, mp_int<0>>)); + BOOST_TEST_TRAIT_TRUE((std::is_same>, mp_true>)); + BOOST_TEST_TRAIT_TRUE((std::is_same>, mp_false>)); - BOOST_TEST_TRAIT_TRUE((std::is_same>, mp_size_t<7>>)); - BOOST_TEST_TRAIT_TRUE((std::is_same>, mp_size_t<0>>)); + BOOST_TEST_TRAIT_TRUE((std::is_same>, mp_true>)); + BOOST_TEST_TRAIT_TRUE((std::is_same>, mp_false>)); BOOST_TEST_TRAIT_TRUE((std::is_same, mp_true>)); BOOST_TEST_TRAIT_TRUE((std::is_same, mp_false>)); BOOST_TEST_TRAIT_TRUE((std::is_same, mp_false>)); - BOOST_TEST_TRAIT_TRUE((std::is_same, mp_int<5>>, mp_int<5>>)); - BOOST_TEST_TRAIT_TRUE((std::is_same, mp_int<0>>, mp_int<0>>)); - BOOST_TEST_TRAIT_TRUE((std::is_same, void>, mp_int<0>>)); + BOOST_TEST_TRAIT_TRUE((std::is_same, mp_int<5>>, mp_true>)); + BOOST_TEST_TRAIT_TRUE((std::is_same, mp_int<0>>, mp_false>)); + BOOST_TEST_TRAIT_TRUE((std::is_same, void>, mp_false>)); - BOOST_TEST_TRAIT_TRUE((std::is_same, mp_size_t<8>>, mp_size_t<8>>)); - BOOST_TEST_TRAIT_TRUE((std::is_same, mp_size_t<0>>, mp_size_t<0>>)); - BOOST_TEST_TRAIT_TRUE((std::is_same, void>, mp_size_t<0>>)); + BOOST_TEST_TRAIT_TRUE((std::is_same, mp_size_t<8>>, mp_true>)); + BOOST_TEST_TRAIT_TRUE((std::is_same, mp_size_t<0>>, mp_false>)); + BOOST_TEST_TRAIT_TRUE((std::is_same, void>, mp_false>)); BOOST_TEST_TRAIT_TRUE((std::is_same, mp_true>)); BOOST_TEST_TRAIT_TRUE((std::is_same, mp_false>)); @@ -54,11 +54,11 @@ int main() BOOST_TEST_TRAIT_TRUE((std::is_same, mp_false>)); BOOST_TEST_TRAIT_TRUE((std::is_same, mp_false>)); - BOOST_TEST_TRAIT_TRUE((std::is_same, mp_int<2>, mp_int<-11>, mp_int<14>>, mp_int<14>>)); - BOOST_TEST_TRAIT_TRUE((std::is_same, mp_int<0>, void, void>, mp_int<0>>)); + BOOST_TEST_TRAIT_TRUE((std::is_same, mp_int<2>, mp_int<-11>, mp_int<14>>, mp_true>)); + BOOST_TEST_TRAIT_TRUE((std::is_same, mp_int<0>, void, void>, mp_false>)); - BOOST_TEST_TRAIT_TRUE((std::is_same, mp_size_t<2>, mp_size_t<114>, mp_size_t<8>, mp_size_t<94>>, mp_size_t<94>>)); - BOOST_TEST_TRAIT_TRUE((std::is_same, mp_size_t<2>, mp_size_t<0>, void, void>, mp_size_t<0>>)); + BOOST_TEST_TRAIT_TRUE((std::is_same, mp_size_t<2>, mp_size_t<114>, mp_size_t<8>, mp_size_t<94>>, mp_true>)); + BOOST_TEST_TRAIT_TRUE((std::is_same, mp_size_t<2>, mp_size_t<0>, void, void>, mp_false>)); return boost::report_errors(); } diff --git a/test/mp_or.cpp b/test/mp_or.cpp index 24190cf..f88097e 100644 --- a/test/mp_or.cpp +++ b/test/mp_or.cpp @@ -25,23 +25,23 @@ int main() BOOST_TEST_TRAIT_TRUE((std::is_same, mp_true>)); BOOST_TEST_TRAIT_TRUE((std::is_same, mp_false>)); - BOOST_TEST_TRAIT_TRUE((std::is_same>, mp_int<-7>>)); - BOOST_TEST_TRAIT_TRUE((std::is_same>, mp_int<0>>)); + BOOST_TEST_TRAIT_TRUE((std::is_same>, mp_true>)); + BOOST_TEST_TRAIT_TRUE((std::is_same>, mp_false>)); - BOOST_TEST_TRAIT_TRUE((std::is_same>, mp_size_t<7>>)); - BOOST_TEST_TRAIT_TRUE((std::is_same>, mp_size_t<0>>)); + BOOST_TEST_TRAIT_TRUE((std::is_same>, mp_true>)); + BOOST_TEST_TRAIT_TRUE((std::is_same>, mp_false>)); BOOST_TEST_TRAIT_TRUE((std::is_same, mp_true>)); BOOST_TEST_TRAIT_TRUE((std::is_same, mp_true>)); BOOST_TEST_TRAIT_TRUE((std::is_same, mp_false>)); - BOOST_TEST_TRAIT_TRUE((std::is_same, mp_int<0>>, mp_int<0>>)); - BOOST_TEST_TRAIT_TRUE((std::is_same, mp_int<5>>, mp_int<5>>)); - BOOST_TEST_TRAIT_TRUE((std::is_same, void>, mp_int<-4>>)); + BOOST_TEST_TRAIT_TRUE((std::is_same, mp_int<0>>, mp_false>)); + BOOST_TEST_TRAIT_TRUE((std::is_same, mp_int<5>>, mp_true>)); + BOOST_TEST_TRAIT_TRUE((std::is_same, void>, mp_true>)); - BOOST_TEST_TRAIT_TRUE((std::is_same, void>, mp_size_t<7>>)); - BOOST_TEST_TRAIT_TRUE((std::is_same, mp_size_t<4>>, mp_size_t<4>>)); - BOOST_TEST_TRAIT_TRUE((std::is_same, mp_size_t<0>>, mp_size_t<0>>)); + BOOST_TEST_TRAIT_TRUE((std::is_same, void>, mp_true>)); + BOOST_TEST_TRAIT_TRUE((std::is_same, mp_size_t<4>>, mp_true>)); + BOOST_TEST_TRAIT_TRUE((std::is_same, mp_size_t<0>>, mp_false>)); BOOST_TEST_TRAIT_TRUE((std::is_same, mp_true>)); BOOST_TEST_TRAIT_TRUE((std::is_same, mp_true>)); @@ -54,19 +54,19 @@ int main() BOOST_TEST_TRAIT_TRUE((std::is_same, mp_true>)); BOOST_TEST_TRAIT_TRUE((std::is_same, mp_false>)); - BOOST_TEST_TRAIT_TRUE((std::is_same, void, void, void>, mp_int<1>>)); - BOOST_TEST_TRAIT_TRUE((std::is_same, mp_int<2>, void, void, void>, mp_int<2>>)); - BOOST_TEST_TRAIT_TRUE((std::is_same, mp_int<0>, mp_int<3>, void, void, void>, mp_int<3>>)); - BOOST_TEST_TRAIT_TRUE((std::is_same, mp_int<0>, mp_int<0>, mp_int<4>, void, void, void>, mp_int<4>>)); - BOOST_TEST_TRAIT_TRUE((std::is_same, mp_int<0>, mp_int<0>, mp_int<0>, mp_int<0>>, mp_int<0>>)); + BOOST_TEST_TRAIT_TRUE((std::is_same, void, void, void>, mp_true>)); + BOOST_TEST_TRAIT_TRUE((std::is_same, mp_int<2>, void, void, void>, mp_true>)); + BOOST_TEST_TRAIT_TRUE((std::is_same, mp_int<0>, mp_int<3>, void, void, void>, mp_true>)); + BOOST_TEST_TRAIT_TRUE((std::is_same, mp_int<0>, mp_int<0>, mp_int<4>, void, void, void>, mp_true>)); + BOOST_TEST_TRAIT_TRUE((std::is_same, mp_int<0>, mp_int<0>, mp_int<0>, mp_int<0>>, mp_false>)); - BOOST_TEST_TRAIT_TRUE((std::is_same, void, void, void>, mp_size_t<1>>)); - BOOST_TEST_TRAIT_TRUE((std::is_same, mp_size_t<2>, void, void, void>, mp_size_t<2>>)); - BOOST_TEST_TRAIT_TRUE((std::is_same, mp_size_t<0>, mp_size_t<3>, void, void, void>, mp_size_t<3>>)); - BOOST_TEST_TRAIT_TRUE((std::is_same, mp_size_t<0>, mp_size_t<0>, mp_size_t<4>, void, void, void>, mp_size_t<4>>)); - BOOST_TEST_TRAIT_TRUE((std::is_same, mp_size_t<0>, mp_size_t<0>, mp_size_t<0>, mp_size_t<0>>, mp_size_t<0>>)); + BOOST_TEST_TRAIT_TRUE((std::is_same, void, void, void>, mp_true>)); + BOOST_TEST_TRAIT_TRUE((std::is_same, mp_size_t<2>, void, void, void>, mp_true>)); + BOOST_TEST_TRAIT_TRUE((std::is_same, mp_size_t<0>, mp_size_t<3>, void, void, void>, mp_true>)); + BOOST_TEST_TRAIT_TRUE((std::is_same, mp_size_t<0>, mp_size_t<0>, mp_size_t<4>, void, void, void>, mp_true>)); + BOOST_TEST_TRAIT_TRUE((std::is_same, mp_size_t<0>, mp_size_t<0>, mp_size_t<0>, mp_size_t<0>>, mp_false>)); - BOOST_TEST_TRAIT_TRUE((std::is_same, mp_int<0>, mp_false, mp_size_t<141>, void, void, void>, mp_size_t<141>>)); + BOOST_TEST_TRAIT_TRUE((std::is_same, mp_int<0>, mp_false, mp_size_t<141>, void, void, void>, mp_true>)); BOOST_TEST_TRAIT_TRUE((std::is_same, mp_int<0>, mp_false>, mp_false>)); return boost::report_errors(); From 6b1a2f61562f57839205cb90b1938b9bcabff8e6 Mon Sep 17 00:00:00 2001 From: Peter Dimov Date: Wed, 24 May 2017 01:37:49 +0300 Subject: [PATCH 04/14] Revert mp_or; add mp_void; update documentation --- doc/html/mp11.html | 50 +++++++++++++++++++++++++-------- doc/mp11/function.qbk | 33 +++++++++++++++++++--- include/boost/mp11/function.hpp | 49 +++++++++++--------------------- 3 files changed, 85 insertions(+), 47 deletions(-) diff --git a/doc/html/mp11.html b/doc/html/mp11.html index d671040..61b6950 100644 --- a/doc/html/mp11.html +++ b/doc/html/mp11.html @@ -166,6 +166,7 @@
Helper Metafunctions, <boost/mp11/function.hpp>
+
mp_void<T...>
mp_and<T...>
mp_all<T...>
mp_or<T...>
@@ -2158,6 +2159,16 @@
+
template<class... T> using mp_void = void;
+
+

+ Same as std::void_t from C++17. +

+
+
+
template<class... T> using mp_and = /*...*/;
@@ -2168,12 +2179,17 @@
           if there exists a type U
           in T...
           for which mp_to_bool<U>
-          is mp_false. mp_to_bool<U>
+          is not mp_true. mp_to_bool<U>
           is not evaluated for types after U.
           If no such type exists, mp_and<T...> is an alias for mp_true.
           (mp_and<>
           is mp_true.)
         

+
using R1 = mp_and<mp_true, mp_true>;   // mp_true
+using R2 = mp_and<mp_false, void>;     // mp_false, void is not reached
+using R3 = mp_and<mp_false, mp_false>; // mp_false
+using R4 = mp_and<void, mp_true>;      // mp_false (!)
+

@@ -2194,6 +2210,11 @@ The upside is that mp_all is faster on legacy compilers.

+
using R1 = mp_and<mp_true, mp_true>;   // mp_true
+using R2 = mp_and<mp_false, void>;     // compile-time error
+using R3 = mp_and<mp_false, mp_false>; // mp_false
+using R4 = mp_and<void, mp_true>;      // compile-time error
+

@@ -2203,16 +2224,18 @@

mp_or<T...> - is an alias for mp_true - if there exists a type U - in T... - for which mp_to_bool<U> - is mp_true. mp_to_bool<U> - is not evaluated for types after U. - If no such type exists, mp_or<T...> is an alias for mp_false. - (mp_or<> - is mp_false.) + applies mp_to_bool to the + types in T..., + in order. If the result of an application is mp_true, + mp_or returns mp_true. If all results are mp_false, returns mp_false. + mp_or<> + is mp_false.

+
using R1 = mp_or<mp_true, mp_false>;   // mp_true
+using R2 = mp_or<mp_true, void>;       // mp_true, void is not reached
+using R3 = mp_or<mp_false, mp_false>;  // mp_false
+using R4 = mp_or<void, mp_true>;       // compile-time error
+

@@ -2228,6 +2251,11 @@ otherwise. Same as mp_or, but does not perform short-circuit evaluation.

+
using R1 = mp_any<mp_true, mp_false>;  // mp_true
+using R2 = mp_any<mp_true, void>;      // compile-time error
+using R3 = mp_any<mp_false, mp_false>; // mp_false
+using R4 = mp_any<void, mp_true>;      // compile-time error
+

@@ -2450,7 +2478,7 @@

- +

Last revised: May 23, 2017 at 20:23:39 GMT

Last revised: May 23, 2017 at 22:20:27 GMT


diff --git a/doc/mp11/function.qbk b/doc/mp11/function.qbk index fca535c..20700bf 100644 --- a/doc/mp11/function.qbk +++ b/doc/mp11/function.qbk @@ -8,12 +8,23 @@ [section:function Helper Metafunctions, ``] +[section `mp_void`] + template using mp_void = void; + +Same as `std::void_t` from C++17. +[endsect] + [section `mp_and`] template using mp_and = /*...*/; -`mp_and` is an alias for `mp_false` if there exists a type `U` in `T...` for which `mp_to_bool` is `mp_false`. +`mp_and` is an alias for `mp_false` if there exists a type `U` in `T...` for which `mp_to_bool` is not `mp_true`. `mp_to_bool` is not evaluated for types after `U`. If no such type exists, `mp_and` is an alias for `mp_true`. (`mp_and<>` is `mp_true`.) + + using R1 = mp_and; // mp_true + using R2 = mp_and; // mp_false, void is not reached + using R3 = mp_and; // mp_false + using R4 = mp_and; // mp_false (!) [endsect] [section `mp_all`] @@ -22,14 +33,23 @@ `mp_all` is `mp_true` if `mp_to_bool` is `mp_true` for all types `U` in `T...`, `mp_false` otherwise. Same as `mp_and`, but does not perform short-circuit evaluation. `mp_and` is `mp_false`, but `mp_all` is an error because `void` does not have a nested `value`. The upside is that `mp_all` is faster on legacy compilers. + + using R1 = mp_and; // mp_true + using R2 = mp_and; // compile-time error + using R3 = mp_and; // mp_false + using R4 = mp_and; // compile-time error [endsect] [section `mp_or`] template using mp_or = /*...*/; -`mp_or` is an alias for `mp_true` if there exists a type `U` in `T...` for which `mp_to_bool` is `mp_true`. -`mp_to_bool` is not evaluated for types after `U`. If no such type exists, `mp_or` is an alias for `mp_false`. -(`mp_or<>` is `mp_false`.) +`mp_or` applies `mp_to_bool` to the types in `T...`, in order. If the result of an application is `mp_true`, `mp_or` +returns `mp_true`. If all results are `mp_false`, returns `mp_false`. `mp_or<>` is `mp_false`. + + using R1 = mp_or; // mp_true + using R2 = mp_or; // mp_true, void is not reached + using R3 = mp_or; // mp_false + using R4 = mp_or; // compile-time error [endsect] [section `mp_any`] @@ -37,6 +57,11 @@ is an error because `void` does not have a nested `value`. The upside is that `m `mp_any` is `mp_true` if `mp_to_bool` is `mp_true` for any type `U` in `T...`, `mp_false` otherwise. Same as `mp_or`, but does not perform short-circuit evaluation. + + using R1 = mp_any; // mp_true + using R2 = mp_any; // compile-time error + using R3 = mp_any; // mp_false + using R4 = mp_any; // compile-time error [endsect] [section `mp_same`] diff --git a/include/boost/mp11/function.hpp b/include/boost/mp11/function.hpp index 04d9dae..5b6ef9f 100644 --- a/include/boost/mp11/function.hpp +++ b/include/boost/mp11/function.hpp @@ -19,9 +19,22 @@ namespace boost namespace mp11 { +// mp_void +namespace detail +{ + +template struct mp_void_impl +{ + using type = void; +}; + +} // namespace detail + +template using mp_void = typename detail::mp_void_impl::type; + // mp_and, mp_all -#if BOOST_WORKAROUND( BOOST_MSVC, < 1900 ) +#if BOOST_WORKAROUND( BOOST_MSVC, < 1910 ) namespace detail { @@ -64,9 +77,7 @@ template struct mp_and_impl using type = mp_false; }; -void mp_and_impl_f(...); - -template struct mp_and_impl< mp_list, decltype( mp_and_impl_f( mp_if()... ) ) > +template struct mp_and_impl< mp_list, mp_void...> > { using type = mp_true; }; @@ -78,10 +89,7 @@ template using mp_all = typename detail::mp_and_impl>: #endif -// mp_or, mp_any - -#if BOOST_WORKAROUND( BOOST_MSVC, < 1900 ) - +// mp_or namespace detail { @@ -111,32 +119,9 @@ template struct mp_or_impl } // namespace detail +// mp_any template using mp_any = mp_bool< mp_count_if< mp_list, mp_to_bool >::value != 0 >; -#else - -namespace detail -{ - -template struct mp_or_impl -{ - using type = mp_true; -}; - -void mp_and_impl_f(...); - -template struct mp_or_impl< mp_list, decltype( mp_and_impl_f( mp_if, int>()... ) ) > -{ - using type = mp_false; -}; - -} // namespace detail - -template using mp_or = typename detail::mp_or_impl>::type; -template using mp_any = typename detail::mp_or_impl>::type; - -#endif - // mp_same namespace detail { From 3e40aacce559982afc8920c9c486f962b285976f Mon Sep 17 00:00:00 2001 From: Peter Dimov Date: Wed, 24 May 2017 01:52:11 +0300 Subject: [PATCH 05/14] Document mp_plus --- doc/html/mp11.html | 17 ++++++++++++++++- doc/mp11/function.qbk | 7 +++++++ include/boost/mp11/function.hpp | 1 + test/Jamfile.v2 | 1 + test/mp_plus.cpp | 32 ++++++++++++++++++++++++++++++++ 5 files changed, 57 insertions(+), 1 deletion(-) create mode 100644 test/mp_plus.cpp diff --git a/doc/html/mp11.html b/doc/html/mp11.html index 61b6950..eff6909 100644 --- a/doc/html/mp11.html +++ b/doc/html/mp11.html @@ -172,6 +172,7 @@
mp_or<T...>
mp_any<T...>
mp_same<T...>
+
mp_plus<T...>
Bind, <boost/mp11/bind.hpp>
@@ -2272,6 +2273,20 @@ is mp_true.

+
+ +
template<class... T> using mp_plus = /*...*/;
+
+

+ mp_plus<T...> + is an integral constant type with a value that is the sum of U::value + for all types U in T.... + mp_plus<> + is mp_int<0>. +

+

@@ -2478,7 +2493,7 @@

- +

Last revised: May 23, 2017 at 22:20:27 GMT

Last revised: May 23, 2017 at 22:51:13 GMT


diff --git a/doc/mp11/function.qbk b/doc/mp11/function.qbk index 20700bf..52bab9a 100644 --- a/doc/mp11/function.qbk +++ b/doc/mp11/function.qbk @@ -70,4 +70,11 @@ returns `mp_true`. If all results are `mp_false`, returns `mp_false`. `mp_or<>` `mp_same` is `mp_true` if all the types in `T...` are the same type, `mp_false` otherwise. `mp_same<>` is `mp_true`. [endsect] +[section `mp_plus`] + template using mp_plus = /*...*/; + +`mp_plus` is an integral constant type with a value that is the sum of `U::value` for all types `U` in `T...`. +`mp_plus<>` is `mp_int<0>`. +[endsect] + [endsect:function] diff --git a/include/boost/mp11/function.hpp b/include/boost/mp11/function.hpp index 5b6ef9f..9821f1d 100644 --- a/include/boost/mp11/function.hpp +++ b/include/boost/mp11/function.hpp @@ -12,6 +12,7 @@ #include #include #include +#include #include namespace boost diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index e700170..277bc4f 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -103,6 +103,7 @@ run mp_and.cpp : : : $(REQ) ; run mp_any.cpp : : : $(REQ) ; run mp_or.cpp : : : $(REQ) ; run mp_same.cpp : : : $(REQ) ; +run mp_plus.cpp : : : $(REQ) ; # map run mp_map_find.cpp : : : $(REQ) ; diff --git a/test/mp_plus.cpp b/test/mp_plus.cpp new file mode 100644 index 0000000..06c05d2 --- /dev/null +++ b/test/mp_plus.cpp @@ -0,0 +1,32 @@ + +// Copyright 2015-2017 Peter Dimov. +// +// 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 + +template using integral = std::integral_constant; + +int main() +{ + using boost::mp11::mp_plus; + + BOOST_TEST_TRAIT_TRUE((std::is_same, integral>)); + + BOOST_TEST_TRAIT_TRUE((std::is_same>, integral>)); + BOOST_TEST_TRAIT_TRUE((std::is_same>, integral>)); + BOOST_TEST_TRAIT_TRUE((std::is_same>, integral>)); + BOOST_TEST_TRAIT_TRUE((std::is_same>, integral>)); + + BOOST_TEST_TRAIT_TRUE((std::is_same, integral>, integral>)); + BOOST_TEST_TRAIT_TRUE((std::is_same, integral, integral>, integral>)); + BOOST_TEST_TRAIT_TRUE((std::is_same, integral, integral, integral>, integral>)); + + return boost::report_errors(); +} From 2bd7393365a79265463bd3782f83ecf66b916949 Mon Sep 17 00:00:00 2001 From: Peter Dimov Date: Wed, 24 May 2017 02:50:43 +0300 Subject: [PATCH 06/14] Use fold expressions in mp_plus --- include/boost/mp11/detail/mp_plus.hpp | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/include/boost/mp11/detail/mp_plus.hpp b/include/boost/mp11/detail/mp_plus.hpp index c27e6de..57cf3cc 100644 --- a/include/boost/mp11/detail/mp_plus.hpp +++ b/include/boost/mp11/detail/mp_plus.hpp @@ -8,7 +8,7 @@ // See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt -#include +#include #include namespace boost @@ -20,6 +20,16 @@ namespace mp11 namespace detail { +#if defined( BOOST_MP11_HAS_FOLD_EXPRESSIONS ) + +template struct mp_plus_impl +{ + static const auto _v = (T::value + ... + 0); + using type = std::integral_constant::type, _v>; +}; + +#else + template struct mp_plus_impl; template<> struct mp_plus_impl<> @@ -29,16 +39,18 @@ template<> struct mp_plus_impl<> template struct mp_plus_impl { - static const/*expr*/ auto _v = T1::value + mp_plus_impl::type::value; + static const auto _v = T1::value + mp_plus_impl::type::value; using type = std::integral_constant::type, _v>; }; template struct mp_plus_impl { - static const/*expr*/ auto _v = T1::value + T2::value + T3::value + T4::value + T5::value + T6::value + T7::value + T8::value + T9::value + T10::value + mp_plus_impl::type::value; + static const auto _v = T1::value + T2::value + T3::value + T4::value + T5::value + T6::value + T7::value + T8::value + T9::value + T10::value + mp_plus_impl::type::value; using type = std::integral_constant::type, _v>; }; +#endif + } // namespace detail template using mp_plus = typename detail::mp_plus_impl::type; From b306ab25aa7d648485d57a59d38dd534b7250511 Mon Sep 17 00:00:00 2001 From: Peter Dimov Date: Wed, 24 May 2017 03:47:24 +0300 Subject: [PATCH 07/14] Do not use auto on g++ 4.7 in mp_plus --- include/boost/mp11/detail/mp_plus.hpp | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/include/boost/mp11/detail/mp_plus.hpp b/include/boost/mp11/detail/mp_plus.hpp index 57cf3cc..1028fa5 100644 --- a/include/boost/mp11/detail/mp_plus.hpp +++ b/include/boost/mp11/detail/mp_plus.hpp @@ -9,6 +9,7 @@ // http://www.boost.org/LICENSE_1_0.txt #include +#include #include namespace boost @@ -37,6 +38,24 @@ template<> struct mp_plus_impl<> using type = std::integral_constant; }; +#if BOOST_WORKAROUND( BOOST_GCC, < 40800 ) + +template struct mp_plus_impl +{ + static const decltype(T1::value + mp_plus_impl::type::value) _v = T1::value + mp_plus_impl::type::value; + using type = std::integral_constant::type, _v>; +}; + +template struct mp_plus_impl +{ + static const + decltype(T1::value + T2::value + T3::value + T4::value + T5::value + T6::value + T7::value + T8::value + T9::value + T10::value + mp_plus_impl::type::value) + _v = T1::value + T2::value + T3::value + T4::value + T5::value + T6::value + T7::value + T8::value + T9::value + T10::value + mp_plus_impl::type::value; + using type = std::integral_constant::type, _v>; +}; + +#else + template struct mp_plus_impl { static const auto _v = T1::value + mp_plus_impl::type::value; @@ -51,6 +70,8 @@ template using mp_plus = typename detail::mp_plus_impl::type; From 8621bb33fb75a7418b4743b20f6996f259d8687e Mon Sep 17 00:00:00 2001 From: Peter Dimov Date: Wed, 24 May 2017 04:09:11 +0300 Subject: [PATCH 08/14] Remove mp_plus 4.7 test workarounds --- test/mp_fold.cpp | 8 -------- test/mp_reverse.cpp | 8 -------- test/mp_reverse_fold.cpp | 8 -------- 3 files changed, 24 deletions(-) diff --git a/test/mp_fold.cpp b/test/mp_fold.cpp index de4ec9a..ee1e422 100644 --- a/test/mp_fold.cpp +++ b/test/mp_fold.cpp @@ -23,16 +23,8 @@ struct X4 {}; template struct F {}; -#if BOOST_WORKAROUND( BOOST_GCC, < 40800 ) - -template using mp_plus = std::integral_constant::type, A::value + B::value>; - -#else - using boost::mp11::mp_plus; -#endif - int main() { using boost::mp11::mp_list; diff --git a/test/mp_reverse.cpp b/test/mp_reverse.cpp index 0035808..74c5461 100644 --- a/test/mp_reverse.cpp +++ b/test/mp_reverse.cpp @@ -29,16 +29,8 @@ struct X10 {}; struct X11 {}; struct X12 {}; -#if BOOST_WORKAROUND( BOOST_GCC, < 40800 ) - -template using mp_plus = std::integral_constant::type, A::value + B::value>; - -#else - using boost::mp11::mp_plus; -#endif - int main() { using boost::mp11::mp_list; diff --git a/test/mp_reverse_fold.cpp b/test/mp_reverse_fold.cpp index 820f64b..3bba659 100644 --- a/test/mp_reverse_fold.cpp +++ b/test/mp_reverse_fold.cpp @@ -29,16 +29,8 @@ using boost::mp11::mp_push_front; template using rev_push_back = mp_push_back; template using rev_push_front = mp_push_front; -#if BOOST_WORKAROUND( BOOST_GCC, < 40800 ) - -template using mp_plus = std::integral_constant::type, A::value + B::value>; - -#else - using boost::mp11::mp_plus; -#endif - int main() { using boost::mp11::mp_list; From ecd77ab9fa662b8c27ad3585a30037b55539a376 Mon Sep 17 00:00:00 2001 From: Peter Dimov Date: Wed, 24 May 2017 04:27:36 +0300 Subject: [PATCH 09/14] Make mp_all fail when ::value is invalid for some type --- include/boost/mp11/function.hpp | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/include/boost/mp11/function.hpp b/include/boost/mp11/function.hpp index 9821f1d..559ac67 100644 --- a/include/boost/mp11/function.hpp +++ b/include/boost/mp11/function.hpp @@ -33,8 +33,7 @@ template struct mp_void_impl template using mp_void = typename detail::mp_void_impl::type; -// mp_and, mp_all - +// mp_and #if BOOST_WORKAROUND( BOOST_MSVC, < 1910 ) namespace detail @@ -66,8 +65,6 @@ template struct mp_and_impl } // namespace detail -template using mp_all = mp_bool< mp_count_if< mp_list, mp_to_bool >::value == sizeof...(T) >; - #else namespace detail @@ -86,7 +83,17 @@ template struct mp_and_impl< mp_list, mp_void.. } // namespace detail template using mp_and = typename detail::mp_and_impl>::type; -template using mp_all = typename detail::mp_and_impl>::type; + +#endif + +// mp_all +#if BOOST_WORKAROUND( BOOST_MSVC, <= 1910 ) + +template using mp_all = mp_bool< mp_count_if< mp_list, mp_to_bool >::value == sizeof...(T) >; + +#else + +template using mp_all = mp_and...>; #endif From fc562c74211649e8beeb2427955a5bfe180239d9 Mon Sep 17 00:00:00 2001 From: Peter Dimov Date: Wed, 24 May 2017 04:59:15 +0300 Subject: [PATCH 10/14] Fix mp_all on g++ 4.7 --- include/boost/mp11/function.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/boost/mp11/function.hpp b/include/boost/mp11/function.hpp index 559ac67..7fe92cf 100644 --- a/include/boost/mp11/function.hpp +++ b/include/boost/mp11/function.hpp @@ -87,7 +87,7 @@ template using mp_and = typename detail::mp_and_impl>: #endif // mp_all -#if BOOST_WORKAROUND( BOOST_MSVC, <= 1910 ) +#if BOOST_WORKAROUND( BOOST_MSVC, <= 1910 ) || BOOST_WORKAROUND( BOOST_GCC, < 40800 ) template using mp_all = mp_bool< mp_count_if< mp_list, mp_to_bool >::value == sizeof...(T) >; From 17b312e14ec3ccbf4d6a863933cb4f2ae7e3af3c Mon Sep 17 00:00:00 2001 From: Peter Dimov Date: Wed, 24 May 2017 05:09:53 +0300 Subject: [PATCH 11/14] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 6cfe82b..db3942d 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ For background, please see the article ["Simple C++11 metaprogramming"](http://pdimov.com/cpp2/simple_cxx11_metaprogramming.html). -The library should be placed in a subdirectory `libs/mp11` in a Boost distribution. There is reference documentation in `doc/html/mp11.html`. +The library should be placed in a subdirectory `libs/mp11` in a Boost distribution. There is [documentation](https://rawgit.com/pdimov/mp11/master/doc/html/mp11.html) in `doc/html/mp11.html`. Supported compilers: From 8e1da779045e69c882a024d06a61a68e7272700c Mon Sep 17 00:00:00 2001 From: Peter Dimov Date: Wed, 24 May 2017 05:58:06 +0300 Subject: [PATCH 12/14] Update documentation --- doc/html/mp11.html | 21 ++++++++++----------- doc/mp11/function.qbk | 9 +++++---- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/doc/html/mp11.html b/doc/html/mp11.html index eff6909..f35da32 100644 --- a/doc/html/mp11.html +++ b/doc/html/mp11.html @@ -2176,15 +2176,14 @@

mp_and<T...> - is an alias for mp_false - if there exists a type U - in T... - for which mp_to_bool<U> - is not mp_true. mp_to_bool<U> - is not evaluated for types after U. - If no such type exists, mp_and<T...> is an alias for mp_true. - (mp_and<> - is mp_true.) + applies mp_to_bool to the + types in T..., + in order. If the result of an application is mp_false, + mp_and returns mp_false. If the application causes a + substitution failure, returns mp_false. + If all results are mp_true, + returns mp_true. mp_and<> + is mp_true.

using R1 = mp_and<mp_true, mp_true>;   // mp_true
 using R2 = mp_and<mp_false, void>;     // mp_false, void is not reached
@@ -2209,7 +2208,7 @@
           is an error because void does
           not have a nested value.
           The upside is that mp_all
-          is faster on legacy compilers.
+          is potentially faster and does not mask substitution failures as mp_and does.
         

using R1 = mp_and<mp_true, mp_true>;   // mp_true
 using R2 = mp_and<mp_false, void>;     // compile-time error
@@ -2493,7 +2492,7 @@
 
- +

Last revised: May 23, 2017 at 22:51:13 GMT

Last revised: May 24, 2017 at 02:43:53 GMT


diff --git a/doc/mp11/function.qbk b/doc/mp11/function.qbk index 52bab9a..ab1cb96 100644 --- a/doc/mp11/function.qbk +++ b/doc/mp11/function.qbk @@ -17,9 +17,9 @@ Same as `std::void_t` from C++17. [section `mp_and`] template using mp_and = /*...*/; -`mp_and` is an alias for `mp_false` if there exists a type `U` in `T...` for which `mp_to_bool` is not `mp_true`. -`mp_to_bool` is not evaluated for types after `U`. If no such type exists, `mp_and` is an alias for `mp_true`. -(`mp_and<>` is `mp_true`.) +`mp_and` applies `mp_to_bool` to the types in `T...`, in order. If the result of an application is `mp_false`, `mp_and` +returns `mp_false`. If the application causes a substitution failure, returns `mp_false`. If all results are `mp_true`, +returns `mp_true`. `mp_and<>` is `mp_true`. using R1 = mp_and; // mp_true using R2 = mp_and; // mp_false, void is not reached @@ -32,7 +32,8 @@ Same as `std::void_t` from C++17. `mp_all` is `mp_true` if `mp_to_bool` is `mp_true` for all types `U` in `T...`, `mp_false` otherwise. Same as `mp_and`, but does not perform short-circuit evaluation. `mp_and` is `mp_false`, but `mp_all` -is an error because `void` does not have a nested `value`. The upside is that `mp_all` is faster on legacy compilers. +is an error because `void` does not have a nested `value`. The upside is that `mp_all` is potentially faster and does not +mask substitution failures as `mp_and` does. using R1 = mp_and; // mp_true using R2 = mp_and; // compile-time error From e81ce26bf96e17c9e5598d03b2589edec999a645 Mon Sep 17 00:00:00 2001 From: Peter Dimov Date: Wed, 24 May 2017 05:59:15 +0300 Subject: [PATCH 13/14] Use fold expressions in mp_all, mp_any --- include/boost/mp11/function.hpp | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/include/boost/mp11/function.hpp b/include/boost/mp11/function.hpp index 7fe92cf..24054b6 100644 --- a/include/boost/mp11/function.hpp +++ b/include/boost/mp11/function.hpp @@ -91,6 +91,10 @@ template using mp_and = typename detail::mp_and_impl>: template using mp_all = mp_bool< mp_count_if< mp_list, mp_to_bool >::value == sizeof...(T) >; +#elif defined( BOOST_MP11_HAS_FOLD_EXPRESSIONS ) + +template using mp_all = mp_bool<(static_cast(T::value) && ...)>; + #else template using mp_all = mp_and...>; @@ -128,8 +132,16 @@ template struct mp_or_impl } // namespace detail // mp_any +#if defined( BOOST_MP11_HAS_FOLD_EXPRESSIONS ) + +template using mp_any = mp_bool<(static_cast(T::value) || ...)>; + +#else + template using mp_any = mp_bool< mp_count_if< mp_list, mp_to_bool >::value != 0 >; +#endif + // mp_same namespace detail { From 0e0d7fae4ec7a0da71f691376419b5b0b5706da8 Mon Sep 17 00:00:00 2001 From: Peter Dimov Date: Wed, 24 May 2017 06:16:17 +0300 Subject: [PATCH 14/14] Enable fold expressions on g++ --- include/boost/mp11/algorithm.hpp | 4 ++-- include/boost/mp11/detail/config.hpp | 6 +++++- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/include/boost/mp11/algorithm.hpp b/include/boost/mp11/algorithm.hpp index 9f0a6f7..e31e3b7 100644 --- a/include/boost/mp11/algorithm.hpp +++ b/include/boost/mp11/algorithm.hpp @@ -499,7 +499,7 @@ namespace detail template struct mp_find_impl; -#if defined( BOOST_MP11_HAS_FOLD_EXPRESSIONS ) +#if defined( BOOST_CLANG ) && defined( BOOST_MP11_HAS_FOLD_EXPRESSIONS ) struct mp_index_holder { @@ -589,7 +589,7 @@ namespace detail template class P> struct mp_find_if_impl; -#if defined( BOOST_MP11_HAS_FOLD_EXPRESSIONS ) +#if defined( BOOST_CLANG ) && defined( BOOST_MP11_HAS_FOLD_EXPRESSIONS ) template class L, class... T, template class P> struct mp_find_if_impl, P> { diff --git a/include/boost/mp11/detail/config.hpp b/include/boost/mp11/detail/config.hpp index 75c5caa..a152f46 100644 --- a/include/boost/mp11/detail/config.hpp +++ b/include/boost/mp11/detail/config.hpp @@ -21,7 +21,11 @@ #endif -#if defined(BOOST_CLANG) && defined(__has_cpp_attribute) +#if defined(__cpp_fold_expressions) && __cpp_fold_expressions >= 201603 + +# define BOOST_MP11_HAS_FOLD_EXPRESSIONS + +#elif defined(BOOST_CLANG) && defined(__has_cpp_attribute) # if __has_cpp_attribute(fallthrough) && __cplusplus >= 201406L // Clang 3.9+ in c++1z mode # define BOOST_MP11_HAS_FOLD_EXPRESSIONS