diff --git a/doc/html/mp11.html b/doc/html/mp11.html index 64d4482..706b518 100644 --- a/doc/html/mp11.html +++ b/doc/html/mp11.html @@ -38,6 +38,8 @@
Generating Test Cases
+
Writing + common_type specializations
Fixing tuple_cat
Computing Return Types
@@ -84,13 +86,15 @@
mp_identity<T>
mp_identity_t<T>
mp_inherit<T...>
-
mp_if_c<B, T, E>
+
mp_if_c<C, T, E...>
mp_if<C, - T, E>
-
mp_eval_if_c<B, T, F, + T, E...>
+
mp_eval_if_c<C, T, F, U...>
mp_eval_if<C, T, F, U...>
+
mp_eval_if_q<C, T, Q, + U...>
mp_valid<F, T...>
mp_defer<F, T...>
mp_quote<F>
@@ -166,6 +170,7 @@
mp_all<T...>
mp_or<T...>
mp_any<T...>
+
mp_same<T...>
Bind, <boost/mp11/bind.hpp>
@@ -400,6 +405,102 @@
+

+ The standard trait std::common_type, used to obtain a type to which + all of its arguments can convert without unnecessary loss of precision, can + be user-specialized when its default implementation (based on the ternary + ?: 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<class Tp1, class Tp2> using common_tuple = mp_transform<std::common_type_t, Tp1, Tp2>;
+
+

+ then specialize common_type + to use it: +

+
namespace std
+{
+
+    template<class... T1, class... T2> struct common_type<std::tuple<T1...>, std::tuple<T2...>>: mp_defer<common_tuple, std::tuple<T1...>, std::tuple<T2...>>
+    {
+    };
+
+} // std
+
+

+ (There is no need to specialize std::common_type + for more than two arguments - it takes care of synthesizing the appropriate + semantics from the binary case.) +

+

+ The subtlety here is the use of mp_defer. + We could have defined a nested type + to common_tuple<std::tuple<T1...>, std::tuple<T2...>>, and it would still have worked + in all valid cases. By letting mp_defer + define type, though, we make + our specialization SFINAE-friendly. +

+

+ That is, when our common_tuple + causes a substitution failure instead of a hard error, mp_defer + will not define a nested type, + and common_type_t, which + is defined as typename common_type<...>::type, + will also cause a substitution failure. +

+

+ As another example, consider the hypothetical type expected<T, + E...> + 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<T1, E1, + 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. +

+

+ 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>;
+
+namespace std
+{
+
+    template<class T1, class... E1, class T2, class... E2> struct common_type<expected<T1, E1...>, expected<T2, E2...>>: mp_defer<common_expected, T1, mp_list<E1...>, T2, mp_list<E2...>>
+    {
+    };
+
+} // std
+
+

+ 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<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> + to the front via mp_push_front; + and finally, we mp_rename + the resultant mp_list to + expected. +

+
+
+

@@ -473,7 +574,7 @@

std::array<int, 2> t1{ 1, 2 };
 std::array<float, 3> t2{ 3.0f, 4.0f, 5.0f };
 
-auto result = ::tuple_cat( t1, std::move( t2 ) );
+auto result = ::tuple_cat( t1, t2 );
 

Let's fix these one by one. Support for move-only types is easy, if one knows @@ -541,11 +642,11 @@

What we need is, given a tuple-like type Tp, to obtain mp_list<std::tuple_element<0, - Tp>, - std::tuple_element<1, Tp>, ..., std::tuple_element<N-1, Tp>>, where N + Tp>::type, std::tuple_element<1, + Tp>::type, ..., std::tuple_element<N-1, Tp>::type>, where N is tuple_size<Tp>::value. Here's one way to do it:

-
template<class T, class I> using tuple_element = std::tuple_element_t<I::value, T>;
+
template<class T, class I> using tuple_element = typename std::tuple_element<I::value, T>::type;
 template<class T> using from_tuple_like = mp_product<tuple_element, mp_list<T>, mp_iota<std::tuple_size<T>>>;
 

@@ -590,7 +691,7 @@ template<class T> using remove_cv_ref = typename std::remove_cv< typename std::remove_reference<T>::type>::type; -template<class T, class I> using tuple_element = std::tuple_element_t<I::value, T>; +template<class T, class I> using tuple_element = typename std::tuple_element<I::value, T>::type; template<class T> using from_tuple_like = mp_product<tuple_element, mp_list<T>, mp_iota<std::tuple_size<T>>>; template<class... Tp, @@ -1209,43 +1310,45 @@

-
template<bool C, class T, class E> using mp_if_c = /*...*/;
+
template<bool C, class T, class... E> using mp_if_c = /*...*/;
 

- mp_if_c<B, T, E> - is an alias for T when - B is true, - for E otherwise. + mp_if_c<true, T, E...> + is an alias for T. mp_if_c<false, T, E> is an alias for E. + Otherwise, the result is a substitution failure. +

+
using R1 = mp_if_c<true, int, void>;  // int
+using R2 = mp_if_c<flase, int, void>; // void
+
+template<class I> using void_if_5 = mp_if_c<I::value == 5, void>; // `void` when `I::value` is 5, substitution failure otherwise
+
+
+
+ +
template<class C, class T, class E...> using mp_if = mp_if_c<static_cast<bool>(C::value), T, E...>;
+
+

+ Like mp_if_c, but the first + argument is a type.

-
template<class C, class T, class E> using mp_if = mp_if_c<static_cast<bool>(C::value), T, E>;
-
-

- mp_if<C, T, E> - is an alias for T when - C::value is true, - for E otherwise. -

-
-
-
template<bool C, class T, template<class...> class F, class... U> using mp_eval_if_c = /*...*/;
 

- mp_eval_if_c<B, T, F, + mp_eval_if_c<C, T, F, U...> is an alias for T when - B is true, + C is true, for F<U...> otherwise. Its purpose is to avoid evaluating F<U...> when the condition is true as it may not be valid in this case.

@@ -1264,6 +1367,18 @@
+
template<class C, class T, class Q, class... U> using mp_eval_if_q = mp_eval_if<C, T, Q::template fn, U...>;
+
+

+ Like mp_eval_if, but takes + a quoted metafunction. +

+
+
+
template<template<class...> class F, class... T> using mp_valid = /*...*/;
@@ -2087,6 +2202,21 @@
           but does not perform short-circuit evaluation.
         

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

+ mp_same<T...> + is mp_true if all the types + in T... + are the same type, mp_false + otherwise. mp_same<> + is mp_true. +

+

@@ -2299,7 +2429,7 @@

- +

Last revised: May 17, 2017 at 17:44:23 GMT

Last revised: May 18, 2017 at 23:57:52 GMT


diff --git a/doc/mp11/examples.qbk b/doc/mp11/examples.qbk index 9d85678..93aad48 100644 --- a/doc/mp11/examples.qbk +++ b/doc/mp11/examples.qbk @@ -87,6 +87,62 @@ tuple element; we use a (C++14) lambda that calls `test_result`. (In pure C++11, function object with a templated `operator()` and pass that to `tuple_for_each` directly.) [endsect] +[section Writing `common_type` specializations] + +The standard trait `std::common_type`, used to obtain a type to which all of its arguments can convert without +unnecessary loss of precision, can be user-specialized when its default implementation (based on the ternary `?:` +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; + +then specialize `common_type` to use it: + + namespace std + { + + template struct common_type, std::tuple>: mp_defer, std::tuple> + { + }; + + } // std + +(There is no need to specialize `std::common_type` for more than two arguments - it takes care of synthesizing the appropriate semantics from +the binary case.) + +The subtlety here is the use of `mp_defer`. We could have defined a nested `type` to `common_tuple, std::tuple>`, +and it would still have worked in all valid cases. By letting `mp_defer` define `type`, though, we make our specialization /SFINAE-friendly/. + +That is, when our `common_tuple` causes a substitution failure instead of a hard error, `mp_defer` will not define a nested `type`, +and `common_type_t`, which is defined as `typename common_type<...>::type`, will also cause a substitution failure. + +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 +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>; + + namespace std + { + + template struct common_type, expected>: mp_defer, T2, mp_list> + { + }; + + } // std + +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` +to `expected`. + +[endsect] + [section Fixing `tuple_cat`] The article [@http://pdimov.com/cpp2/simple_cxx11_metaprogramming.html Simple C++11 metaprogramming] builds an @@ -148,7 +204,7 @@ that support `tuple_size`, `tuple_element`, and `get`), while our implementation std::array t1{ 1, 2 }; std::array t2{ 3.0f, 4.0f, 5.0f }; - auto result = ::tuple_cat( t1, std::move( t2 ) ); + auto result = ::tuple_cat( t1, t2 ); Let's fix these one by one. Support for move-only types is easy, if one knows where to look. The problem is that `Tp` that we're passing to the helper `tuple_cat_` is (correctly) `tuple&&, unique_ptr&&>`, @@ -193,10 +249,10 @@ the corresponding `mp_list`. Technically, a more principled approach would've been to return `std::tuple`, but here `mp_list` will prove more convenient. -What we need is, given a tuple-like type `Tp`, to obtain `mp_list, std::tuple_element<1, Tp>, -..., std::tuple_element>`, where `N` is `tuple_size::value`. Here's one way to do it: +What we need is, given a tuple-like type `Tp`, to obtain `mp_list::type, std::tuple_element<1, Tp>::type, +..., std::tuple_element::type>`, where `N` is `tuple_size::value`. Here's one way to do it: - template using tuple_element = std::tuple_element_t; + template using tuple_element = typename std::tuple_element::type; template using from_tuple_like = mp_product, mp_iota>>; (`mp_iota` is an algorithm that returns an `mp_list` with elements `mp_size_t<0>`, `mp_size_t<1>`, ..., `mp_size_t`.) @@ -224,7 +280,7 @@ With all these fixes applied, our fully operational `tuple_cat` now looks like t template using remove_cv_ref = typename std::remove_cv< typename std::remove_reference::type>::type; - template using tuple_element = std::tuple_element_t; + template using tuple_element = typename std::tuple_element::type; template using from_tuple_like = mp_product, mp_iota>>; template` is `mp_false`. Simil `mp_or`, but does not perform short-circuit evaluation. [endsect] +[section `mp_same`] + template using mp_same = /*...*/; + +`mp_same` is `mp_true` if all the types in `T...` are the same type, `mp_false` otherwise. `mp_same<>` is `mp_true`. +[endsect] + [endsect:function] diff --git a/doc/mp11/utility.qbk b/doc/mp11/utility.qbk index 1786265..13b6f80 100644 --- a/doc/mp11/utility.qbk +++ b/doc/mp11/utility.qbk @@ -23,22 +23,27 @@ template struct mp_inherit: T... {}; [endsect] -[section `mp_if_c`] - template using mp_if_c = /*...*/; +[section `mp_if_c`] + template using mp_if_c = /*...*/; -`mp_if_c` is an alias for `T` when `B` is `true`, for `E` otherwise. +`mp_if_c` is an alias for `T`. `mp_if_c` is an alias for `E`. Otherwise, the result is a substitution failure. + + using R1 = mp_if_c; // int + using R2 = mp_if_c; // void + + template using void_if_5 = mp_if_c; // `void` when `I::value` is 5, substitution failure otherwise [endsect] -[section `mp_if`] - template using mp_if = mp_if_c(C::value), T, E>; +[section `mp_if`] + template using mp_if = mp_if_c(C::value), T, E...>; -`mp_if` is an alias for `T` when `C::value` is `true`, for `E` otherwise. +Like `mp_if_c`, but the first argument is a type. [endsect] -[section `mp_eval_if_c`] +[section `mp_eval_if_c`] template class F, class... U> using mp_eval_if_c = /*...*/; -`mp_eval_if_c` is an alias for `T` when `B` is `true`, for `F` otherwise. Its purpose +`mp_eval_if_c` is an alias for `T` when `C` is `true`, for `F` otherwise. Its purpose is to avoid evaluating `F` when the condition is `true` as it may not be valid in this case. [endsect] @@ -48,6 +53,12 @@ is to avoid evaluating `F` when the condition is `true` as it may not be v Like `mp_eval_if_c`, but the first argument is a type. [endsect] +[section `mp_eval_if_q`] + template using mp_eval_if_q = mp_eval_if; + +Like `mp_eval_if`, but takes a quoted metafunction. +[endsect] + [section `mp_valid`] template class F, class... T> using mp_valid = /*...*/; diff --git a/include/boost/mp11/algorithm.hpp b/include/boost/mp11/algorithm.hpp index 298c25a..1762502 100644 --- a/include/boost/mp11/algorithm.hpp +++ b/include/boost/mp11/algorithm.hpp @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -59,7 +60,9 @@ template class F> using mp_fold = typename namespace detail { -template class F, class... L> struct mp_transform_impl; +template class F, class... L> struct mp_transform_impl +{ +}; template class F, template class L, class... T> struct mp_transform_impl> { @@ -68,19 +71,33 @@ template class F, template class L, class... T> str template class F, template class L1, class... T1, template class L2, class... T2> struct mp_transform_impl, L2> { - static_assert( sizeof...(T1) == sizeof...(T2), "The arguments of mp_transform should be of the same size" ); using type = L1...>; }; template class F, template class L1, class... T1, template class L2, class... T2, template class L3, class... T3> struct mp_transform_impl, L2, L3> { - static_assert( sizeof...(T1) == sizeof...(T2) && sizeof...(T1) == sizeof...(T3), "The arguments of mp_transform should be of the same size" ); using type = L1...>; }; +#if BOOST_WORKAROUND( BOOST_MSVC, == 1900 ) || BOOST_WORKAROUND( BOOST_GCC, < 40800 ) + +template using mp_same_size_1 = mp_same...>; +template struct mp_same_size_2: mp_defer {}; + +#endif + } // namespace detail -template class F, class... L> using mp_transform = typename detail::mp_transform_impl::type; +#if BOOST_WORKAROUND( BOOST_MSVC, == 1900 ) || BOOST_WORKAROUND( BOOST_GCC, < 40800 ) + +template class F, class... L> using mp_transform = typename mp_if::type, detail::mp_transform_impl>::type; + +#else + +template class F, class... L> using mp_transform = typename mp_if...>, detail::mp_transform_impl>::type; + +#endif + template using mp_transform_q = mp_transform; namespace detail @@ -88,8 +105,6 @@ namespace detail template class F, template class L1, class... T1, template class L2, class... T2, template class L3, class... T3, template class L4, class... T4, class... L> struct mp_transform_impl, L2, L3, L4, L...> { - static_assert( sizeof...(T1) == sizeof...(T2) && sizeof...(T1) == sizeof...(T3) && sizeof...(T1) == sizeof...(T4), "The arguments of mp_transform should be of the same size" ); - using A1 = L1...>; template using _f = mp_transform; diff --git a/include/boost/mp11/utility.hpp b/include/boost/mp11/utility.hpp index e220b5f..35af770 100644 --- a/include/boost/mp11/utility.hpp +++ b/include/boost/mp11/utility.hpp @@ -33,9 +33,11 @@ template struct mp_inherit: T... {}; namespace detail { -template struct mp_if_c_impl; +template struct mp_if_c_impl +{ +}; -template struct mp_if_c_impl +template struct mp_if_c_impl { using type = T; }; @@ -47,29 +49,8 @@ template struct mp_if_c_impl } // namespace detail -template using mp_if_c = typename detail::mp_if_c_impl::type; -template using mp_if = typename detail::mp_if_c_impl(C::value), T, E>::type; - -// mp_eval_if, mp_eval_if_c -namespace detail -{ - -template class F, class... U> struct mp_eval_if_c_impl; - -template class F, class... U> struct mp_eval_if_c_impl -{ - using type = T; -}; - -template class F, class... U> struct mp_eval_if_c_impl -{ - using type = F; -}; - -} // namespace detail - -template class F, class... U> using mp_eval_if_c = typename detail::mp_eval_if_c_impl::type; -template class F, class... U> using mp_eval_if = typename detail::mp_eval_if_c_impl(C::value), T, F, U...>::type; +template using mp_if_c = typename detail::mp_if_c_impl::type; +template using mp_if = typename detail::mp_if_c_impl(C::value), T, E...>::type; // mp_valid // implementation by Bruno Dutra (by the name is_evaluable) @@ -105,37 +86,58 @@ struct mp_no_type template class F, class... T> using mp_defer = mp_if, detail::mp_defer_impl, detail::mp_no_type>; -// mp_quote -template class F> struct mp_quote -{ -#if defined( BOOST_MSVC ) && BOOST_WORKAROUND( BOOST_MSVC, <= 1910 && BOOST_MSVC >= 1900 ) -#else -private: -#endif - - template struct _fn { using type = F; }; - -public: - - // the indirection through _fn works around the language inability - // to expand T... into a fixed parameter list of an alias template - - template using fn = typename _fn::type; -}; - -// mp_unquote +// mp_eval_if, mp_eval_if_c namespace detail { -template struct mp_invoke_impl +template class F, class... U> struct mp_eval_if_c_impl; + +template class F, class... U> struct mp_eval_if_c_impl { - using type = typename Q::template fn; + using type = T; }; +template class F, class... U> struct mp_eval_if_c_impl: mp_defer +{ +}; + +} // namespace detail + +template class F, class... U> using mp_eval_if_c = typename detail::mp_eval_if_c_impl::type; +template class F, class... U> using mp_eval_if = typename detail::mp_eval_if_c_impl(C::value), T, F, U...>::type; +template using mp_eval_if_q = typename detail::mp_eval_if_c_impl(C::value), T, Q::template fn, U...>::type; + +// mp_quote +template class F> struct mp_quote +{ + // the indirection through mp_defer works around the language inability + // to expand T... into a fixed parameter list of an alias template + + template using fn = typename mp_defer::type; +}; + +// mp_invoke +#if BOOST_WORKAROUND( BOOST_MSVC, < 1900 ) + +namespace detail +{ + +template struct mp_invoke_impl: mp_defer {}; + } // namespace detail template using mp_invoke = typename detail::mp_invoke_impl::type; +#elif BOOST_WORKAROUND( BOOST_GCC, < 50000 ) + +template using mp_invoke = typename mp_defer::type; + +#else + +template using mp_invoke = typename Q::template fn; + +#endif + } // namespace mp11 } // namespace boost diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index da5c569..e700170 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -35,6 +35,7 @@ run mp_apply_q.cpp : : : $(REQ) ; run mp_assign.cpp : : : $(REQ) ; run mp_clear.cpp : : : $(REQ) ; run mp_transform.cpp : : : $(REQ) ; +run mp_transform_sf.cpp : : : $(REQ) ; run mp_transform_if.cpp : : : $(REQ) ; run mp_fill.cpp : : : $(REQ) ; run mp_count.cpp : : : $(REQ) ; @@ -75,11 +76,14 @@ run integral.cpp : : : $(REQ) ; run mp_identity.cpp : : : $(REQ) ; run mp_inherit.cpp : : : $(REQ) ; run mp_if.cpp : : : $(REQ) ; +run mp_if_sf.cpp : : : $(REQ) ; run mp_eval_if.cpp : : : $(REQ) ; +run mp_eval_if_sf.cpp : : : $(REQ) ; run mp_valid.cpp : : : $(REQ) ; run mp_defer.cpp : : : $(REQ) ; run mp_quote.cpp : : : $(REQ) ; run mp_invoke.cpp : : : $(REQ) ; +run mp_invoke_sf.cpp : : : $(REQ) ; # integer_sequence run integer_sequence.cpp : : : $(REQ) ; diff --git a/test/mp_eval_if.cpp b/test/mp_eval_if.cpp index 1c8ed39..7e44c67 100644 --- a/test/mp_eval_if.cpp +++ b/test/mp_eval_if.cpp @@ -1,5 +1,5 @@ -// Copyright 2015 Peter Dimov. +// Copyright 2015, 2017 Peter Dimov. // // Distributed under the Boost Software License, Version 1.0. // @@ -21,19 +21,32 @@ int main() BOOST_TEST_TRAIT_TRUE((std::is_same, mp_identity>)); using boost::mp11::mp_eval_if; + using boost::mp11::mp_eval_if_q; + using boost::mp11::mp_quote; + + using qt_identity = mp_quote; BOOST_TEST_TRAIT_TRUE((std::is_same, char[]>)); BOOST_TEST_TRAIT_TRUE((std::is_same, mp_identity>)); + BOOST_TEST_TRAIT_TRUE((std::is_same, char[]>)); + BOOST_TEST_TRAIT_TRUE((std::is_same, mp_identity>)); + using boost::mp11::mp_int; BOOST_TEST_TRAIT_TRUE((std::is_same, char[], mp_identity, void, void, void>, char[]>)); BOOST_TEST_TRAIT_TRUE((std::is_same, char[], mp_identity, void()>, mp_identity>)); + BOOST_TEST_TRAIT_TRUE((std::is_same, char[], qt_identity, void, void, void>, char[]>)); + BOOST_TEST_TRAIT_TRUE((std::is_same, char[], qt_identity, void()>, mp_identity>)); + using boost::mp11::mp_size_t; BOOST_TEST_TRAIT_TRUE((std::is_same, char[], mp_identity, void, void, void>, char[]>)); BOOST_TEST_TRAIT_TRUE((std::is_same, char[], mp_identity, void()>, mp_identity>)); + BOOST_TEST_TRAIT_TRUE((std::is_same, char[], qt_identity, void, void, void>, char[]>)); + BOOST_TEST_TRAIT_TRUE((std::is_same, char[], qt_identity, void()>, mp_identity>)); + return boost::report_errors(); } diff --git a/test/mp_eval_if_sf.cpp b/test/mp_eval_if_sf.cpp new file mode 100644 index 0000000..aed1191 --- /dev/null +++ b/test/mp_eval_if_sf.cpp @@ -0,0 +1,47 @@ + +// Copyright 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 + +using boost::mp11::mp_eval_if; +using boost::mp11::mp_eval_if_q; +using boost::mp11::mp_identity_t; +using boost::mp11::mp_valid; +using boost::mp11::mp_quote; + +template using eval_if = mp_eval_if; + +int main() +{ + BOOST_TEST_TRAIT_TRUE((mp_valid)); + BOOST_TEST_TRAIT_TRUE((mp_valid)); + BOOST_TEST_TRAIT_TRUE((mp_valid)); + BOOST_TEST_TRAIT_TRUE((mp_valid)); + + BOOST_TEST_TRAIT_FALSE((mp_valid)); + BOOST_TEST_TRAIT_TRUE((mp_valid)); + BOOST_TEST_TRAIT_FALSE((mp_valid)); + BOOST_TEST_TRAIT_FALSE((mp_valid)); + + using Qi = mp_quote; + + BOOST_TEST_TRAIT_TRUE((mp_valid)); + BOOST_TEST_TRAIT_TRUE((mp_valid)); + BOOST_TEST_TRAIT_TRUE((mp_valid)); + BOOST_TEST_TRAIT_TRUE((mp_valid)); + + BOOST_TEST_TRAIT_FALSE((mp_valid)); + BOOST_TEST_TRAIT_TRUE((mp_valid)); + BOOST_TEST_TRAIT_FALSE((mp_valid)); + BOOST_TEST_TRAIT_FALSE((mp_valid)); + + return boost::report_errors(); +} diff --git a/test/mp_if_sf.cpp b/test/mp_if_sf.cpp new file mode 100644 index 0000000..15ef309 --- /dev/null +++ b/test/mp_if_sf.cpp @@ -0,0 +1,24 @@ + +// Copyright 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 + +int main() +{ + using boost::mp11::mp_if; + using boost::mp11::mp_valid; + + BOOST_TEST_TRAIT_FALSE((mp_valid)); + BOOST_TEST_TRAIT_TRUE((mp_valid)); + BOOST_TEST_TRAIT_FALSE((mp_valid)); + + return boost::report_errors(); +} diff --git a/test/mp_invoke_sf.cpp b/test/mp_invoke_sf.cpp new file mode 100644 index 0000000..7c2feb6 --- /dev/null +++ b/test/mp_invoke_sf.cpp @@ -0,0 +1,33 @@ + +// 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 + +using boost::mp11::mp_invoke; +using boost::mp11::mp_quote; +using boost::mp11::mp_valid; +using boost::mp11::mp_identity_t; + +int main() +{ + BOOST_TEST_TRAIT_FALSE((mp_valid)); + BOOST_TEST_TRAIT_FALSE((mp_valid)); + BOOST_TEST_TRAIT_FALSE((mp_valid)); + BOOST_TEST_TRAIT_FALSE((mp_valid)); + + using Qi = mp_quote; + + BOOST_TEST_TRAIT_FALSE((mp_valid)); + BOOST_TEST_TRAIT_TRUE((mp_valid)); + BOOST_TEST_TRAIT_FALSE((mp_valid)); + + return boost::report_errors(); +} diff --git a/test/mp_transform_sf.cpp b/test/mp_transform_sf.cpp new file mode 100644 index 0000000..7f18eab --- /dev/null +++ b/test/mp_transform_sf.cpp @@ -0,0 +1,42 @@ + +// Copyright 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 + +using boost::mp11::mp_transform; +using boost::mp11::mp_list; +using boost::mp11::mp_valid; + +template using F = void; + +template using transform = mp_transform; + +int main() +{ + BOOST_TEST_TRAIT_FALSE((mp_valid)); + BOOST_TEST_TRAIT_FALSE((mp_valid)); + BOOST_TEST_TRAIT_FALSE((mp_valid)); + BOOST_TEST_TRAIT_FALSE((mp_valid)); + BOOST_TEST_TRAIT_FALSE((mp_valid)); + BOOST_TEST_TRAIT_FALSE((mp_valid)); + +#if !BOOST_WORKAROUND( BOOST_MSVC, <= 1800 ) + BOOST_TEST_TRAIT_TRUE((mp_valid>)); +#endif + + BOOST_TEST_TRAIT_FALSE((mp_valid, mp_list>)); + BOOST_TEST_TRAIT_FALSE((mp_valid, mp_list<>, mp_list>)); + BOOST_TEST_TRAIT_FALSE((mp_valid, mp_list<>, mp_list<>, mp_list>)); + BOOST_TEST_TRAIT_FALSE((mp_valid, mp_list<>, mp_list<>, mp_list<>, mp_list>)); + + return boost::report_errors(); +}