diff --git a/include/boost/fusion/container/vector/detail/config.hpp b/include/boost/fusion/container/vector/detail/config.hpp index 84f4605d..a80fd69a 100644 --- a/include/boost/fusion/container/vector/detail/config.hpp +++ b/include/boost/fusion/container/vector/detail/config.hpp @@ -15,6 +15,7 @@ || defined(BOOST_NO_CXX11_RVALUE_REFERENCES) \ || defined(BOOST_NO_CXX11_TEMPLATE_ALIASES) \ || defined(BOOST_NO_CXX11_DECLTYPE)) \ + || defined(BOOST_FUSION_DISABLE_VARIADIC_VECTOR) \ || (defined(__WAVE__) && defined(BOOST_FUSION_CREATE_PREPROCESSED_FILES)) # if defined(BOOST_FUSION_HAS_VARIADIC_VECTOR) # undef BOOST_FUSION_HAS_VARIADIC_VECTOR diff --git a/include/boost/fusion/support/detail/and.hpp b/include/boost/fusion/support/detail/and.hpp new file mode 100644 index 00000000..8560f344 --- /dev/null +++ b/include/boost/fusion/support/detail/and.hpp @@ -0,0 +1,35 @@ +/*============================================================================= + Copyright (c) 2016 Lee Clagett + + 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) +==============================================================================*/ +#ifndef FUSION_AND_07152016_1625 +#define FUSION_AND_07152016_1625 + +#include +#include + +#if defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) +#error fusion::detail::and_ requires variadic templates +#endif + +namespace boost { namespace fusion { namespace detail { + template + struct and_impl : false_type {}; + + template + struct and_impl...> : true_type {}; + + /* fusion::detail::and_ differs from mpl::and_ in the following ways: + - The empty set is valid and returns true + - A single element set is valid and returns the identity + - There is no upper bound on the set size + - The conditions are evaluated at once, and are not short-circuited. This + reduces instantations when returning true; the implementation is not + recursive. */ + template + struct and_ : and_impl...> {}; +}}} + +#endif // FUSION_AND_07152016_1625 diff --git a/include/boost/fusion/tuple/tuple.hpp b/include/boost/fusion/tuple/tuple.hpp index 6ee21f56..606e1694 100644 --- a/include/boost/fusion/tuple/tuple.hpp +++ b/include/boost/fusion/tuple/tuple.hpp @@ -20,12 +20,15 @@ /////////////////////////////////////////////////////////////////////////////// // C++11 interface /////////////////////////////////////////////////////////////////////////////// +#include #include #include #include #include #include #include +#include +#include #include namespace boost { namespace fusion @@ -49,13 +52,29 @@ namespace boost { namespace fusion tuple(tuple&& other) : base_type(std::move(other)) {} - template + template < + typename ...U + , typename = typename boost::enable_if_c<( + fusion::detail::and_...>::value && + sizeof...(U) >= 1 + )>::type + > /*BOOST_CONSTEXPR*/ BOOST_FUSION_GPU_ENABLED explicit tuple(U&&... args) : base_type(std::forward(args)...) {} - template + template + BOOST_CONSTEXPR BOOST_FUSION_GPU_ENABLED + tuple(std::pair const& other) + : base_type(other.first, other.second) {} + + template + BOOST_CONSTEXPR BOOST_FUSION_GPU_ENABLED + tuple(std::pair&& other) + : base_type(std::move(other.first), std::move(other.second)) {} + + template BOOST_CXX14_CONSTEXPR BOOST_FUSION_GPU_ENABLED tuple& operator=(U&& rhs) { diff --git a/include/boost/fusion/tuple/tuple_fwd.hpp b/include/boost/fusion/tuple/tuple_fwd.hpp index b763acd5..f3e8deb0 100644 --- a/include/boost/fusion/tuple/tuple_fwd.hpp +++ b/include/boost/fusion/tuple/tuple_fwd.hpp @@ -12,6 +12,7 @@ #include #if !defined(BOOST_FUSION_HAS_VARIADIC_VECTOR) \ + || defined(BOOST_NO_CXX11_FUNCTION_TEMPLATE_DEFAULT_ARGS) \ || (defined(__WAVE__) && defined(BOOST_FUSION_CREATE_PREPROCESSED_FILES)) # if defined(BOOST_FUSION_HAS_VARIADIC_TUPLE) # undef BOOST_FUSION_HAS_VARIADIC_TUPLE diff --git a/test/Jamfile b/test/Jamfile index 8f290165..7e5e4186 100644 --- a/test/Jamfile +++ b/test/Jamfile @@ -131,6 +131,20 @@ project [ run sequence/tuple_nest.cpp : : : : ] [ run sequence/tuple_hash.cpp : : : : ] [ run sequence/tuple_tie.cpp : : : : ] + [ + run sequence/tuple_traits.cpp + : + : + : + : sequence/tuple_traits/maybe_variadic_vector + ] + [ + run sequence/tuple_traits.cpp + : + : + : BOOST_FUSION_DISABLE_VARIADIC_VECTOR + : sequence/tuple_traits/no_variadic_vector + ] [ run sequence/transform_view.cpp : : : : ] [ run sequence/vector_comparison.cpp : : : : ] [ run sequence/vector_construction.cpp : : : : ] @@ -197,6 +211,7 @@ project [ compile support/pair_vector.cpp : : : : ] [ compile support/pair_nest.cpp : : : : ] [ compile support/index_sequence.cpp : : : : ] + [ compile support/and.cpp : : : : ] # [ compile-fail xxx.cpp : : : : ] diff --git a/test/sequence/tuple_construction.cpp b/test/sequence/tuple_construction.cpp index 044701c4..12772027 100644 --- a/test/sequence/tuple_construction.cpp +++ b/test/sequence/tuple_construction.cpp @@ -13,9 +13,37 @@ #define FUSION_AT get #include "construction.hpp" +// Bug in C++03 tuple? Cannot construct from a std::pair without including +// std::pair fusion adaption +#if !defined(BOOST_FUSION_HAS_VARIADIC_TUPLE) +# include +#endif + +struct test_conversion +{ + test_conversion(int value) : value_(value) {} + + int value_; +}; + int main() { test(); + + { + using namespace boost::fusion; + const tuple instance(std::pair(1, 9)); + BOOST_TEST(boost::fusion::get<0>(instance) == 1); + BOOST_TEST(boost::fusion::get<1>(instance).value_ == 9); + } + { + using namespace boost::fusion; + const std::pair init(16, 4); + const tuple instance(init); + BOOST_TEST(boost::fusion::get<0>(instance) == 16); + BOOST_TEST(boost::fusion::get<1>(instance).value_ == 4); + } + return boost::report_errors(); } diff --git a/test/sequence/tuple_traits.cpp b/test/sequence/tuple_traits.cpp new file mode 100644 index 00000000..e13a0076 --- /dev/null +++ b/test/sequence/tuple_traits.cpp @@ -0,0 +1,123 @@ +/*============================================================================= + Copyright (c) 2016 Lee Clagett + + 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 +#include +#include + +struct test_conversion +{ + test_conversion(int) {} +}; + +struct test_no_conversion +{ + explicit test_no_conversion(int) {} +}; + +/* Some construction differences in fusion::tuple from std::tuple: + - Construction from elements cannot call an explicit constructor. + - There is no implicit construction from elements. + - Construction from std::pair is _enabled_ when tuple is not of size 2. + - Construction from tuple is _enabled_ when destination tuple is of + different size. + - Implicit construction from std::pair can call explicit constructors on + elements. + - Implicit construction from tuple can call explicit constructors on + elements. + + These differences are historical. Matching the behavior of std::tuple + could break existing code, however, switching to fusion::vector would + restore the historical behavior. */ +int +main() { + { + using namespace boost; + using namespace boost::fusion; + + BOOST_TEST(!(is_convertible >::value)); + BOOST_TEST(!(is_convertible >::value)); + + BOOST_TEST(!(is_convertible< int, tuple >::value)); + BOOST_TEST(!(is_convertible< int&, tuple >::value)); + BOOST_TEST(!(is_convertible< vector, tuple >::value)); + BOOST_TEST(!(is_convertible< vector&, tuple >::value)); + + BOOST_TEST(!(is_convertible >::value)); + BOOST_TEST(!(is_convertible >::value)); + } + +// is_constructible has some restrictions ... +#if !(defined(BOOST_NO_CXX11_DECLTYPE) || defined(BOOST_NO_CXX11_TEMPLATES) || \ + defined(BOOST_NO_SFINAE_EXPR)) + { + using namespace boost; + using namespace boost::fusion; + + BOOST_TEST((is_constructible< tuple<> >::value)); + BOOST_TEST(!(is_constructible, int>::value)); + BOOST_TEST(!(is_constructible, int&>::value)); + + BOOST_TEST((is_constructible< tuple >::value)); + BOOST_TEST((is_constructible, int>::value)); + BOOST_TEST((is_constructible, int&>::value)); + BOOST_TEST((is_constructible, int>::value)); + BOOST_TEST((is_constructible, int&>::value)); + BOOST_TEST(!(is_constructible, int>::value)); + BOOST_TEST(!(is_constructible, int&>::value)); + BOOST_TEST(!(is_constructible< tuple, vector >::value)); + BOOST_TEST(!(is_constructible, vector&>::value)); + BOOST_TEST(!(is_constructible, int, int>::value)); + BOOST_TEST(!(is_constructible, int&, int&>::value)); + + BOOST_TEST((is_constructible< tuple >::value)); + BOOST_TEST((is_constructible, int, int>::value)); + BOOST_TEST((is_constructible, int&, int&>::value)); + BOOST_TEST(( + is_constructible< + tuple + , int + , int + >::value + )); + BOOST_TEST(( + is_constructible< + tuple + , int& + , int& + >::value + )); + BOOST_TEST(!( + is_constructible< + tuple + , int + , int + >::value + )); + BOOST_TEST(!( + is_constructible< + tuple + , int& + , int& + >::value + )); +#if defined(BOOST_FUSION_HAS_VARIADIC_VECTOR) + // C++03 fusion::tuple has constructors that can never be used + BOOST_TEST(!(is_constructible, int>::value)); + BOOST_TEST(!(is_constructible, int&>::value)); +#endif + BOOST_TEST(!(is_constructible, int, int, int>::value)); + BOOST_TEST(!( + is_constructible, int&, int&, int&>::value + )); + } +#endif + + return boost::report_errors(); +} diff --git a/test/support/and.cpp b/test/support/and.cpp new file mode 100644 index 00000000..99ecd9f4 --- /dev/null +++ b/test/support/and.cpp @@ -0,0 +1,33 @@ +/*============================================================================= + Copyright (c) 2016 Lee Clagett + 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 !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) + +#include +#include +#include +#include + +int main() { + using namespace boost; + using namespace boost::fusion::detail; + + BOOST_TEST((and_<>::value)); + BOOST_TEST(!(and_::value)); + BOOST_TEST((and_::value)); + BOOST_TEST(!(and_::value)); + BOOST_TEST((and_::value)); + BOOST_TEST(!(and_::value)); + BOOST_TEST((and_::value)); + BOOST_TEST((and_::value)); + + return boost::report_errors(); +} + +#endif +