diff --git a/include/boost/test/utils/is_forward_iterable.hpp b/include/boost/test/utils/is_forward_iterable.hpp index ed38b0dc30..202aed2b25 100755 --- a/include/boost/test/utils/is_forward_iterable.hpp +++ b/include/boost/test/utils/is_forward_iterable.hpp @@ -65,31 +65,60 @@ struct is_forward_iterable > : public mpl::true_ {}; namespace ut_detail { -template -struct is_present : public mpl::true_ {}; - -struct is_forward_iterable_impl { - template - static typename std::enable_if< - is_present::value && - is_present::value && - is_present().size())>::value && - is_present().begin())>::value && - !is_same::type,char>::value && - !is_same::type,wchar_t>::value - , mpl::true_>::type - test(int); - - template - static std::false_type test(...); -}; + + template + struct is_present : public mpl::true_ {}; + + + // some compiler do not implement properly decltype non expression involving members (eg. VS2013) + // a workaround is to use -> decltype syntax. + template + struct has_member_size { + private: + struct nil_t; + template static auto test(T*) -> decltype( boost::declval().size() ); + template static nil_t test(...); + + public: + static bool const value = !std::is_same< decltype(test(nullptr)), nil_t>::value; + }; + + template + struct has_member_begin { + private: + struct nil_t; + template static auto test(T*) -> decltype( boost::declval().begin() ); + template static nil_t test(...); + public: + static bool const value = !std::is_same< decltype(test(nullptr)), nil_t>::value; + }; + + + template + struct is_forward_iterable_impl : std::false_type + {}; + + template + struct is_forward_iterable_impl< + T, + typename std::enable_if< + is_present::value && + is_present::value && + has_member_size::value && + has_member_begin::value && + !is_same::type,char>::value && + !is_same::type,wchar_t>::value + >::type + > : std::true_type + {}; + } // namespace ut_detail template -struct is_forward_iterable { - typedef decltype(ut_detail::is_forward_iterable_impl::test::type>(0)) type; - enum { value = type::value }; +struct is_forward_iterable { + typedef mpl::bool_::value> type; + enum { value = ut_detail::is_forward_iterable_impl::value }; }; #endif diff --git a/test/test_assertion_construction.cpp b/test/test_assertion_construction.cpp index 64ab707d2a..7d110d802f 100644 --- a/test/test_assertion_construction.cpp +++ b/test/test_assertion_construction.cpp @@ -14,7 +14,7 @@ // Boost.Test #define BOOST_TEST_MODULE Boost.Test assertion consruction test -#include +#include #include #ifdef BOOST_NO_CXX11_AUTO_DECLARATIONS #include @@ -35,6 +35,102 @@ # define BOOST_TEST_FWD( a ) BOOST_TEST( a ) #endif + +#ifndef BOOST_NO_CXX11_AUTO_DECLARATIONS + +// some broken compilers do not implement properly decltype on expressions +struct not_fwd_iterable_1 { + typedef int const_iterator; + typedef int value_type; + + bool size(); +}; + +struct not_fwd_iterable_2 { + typedef int const_iterator; + typedef int value_type; + + bool begin(); +}; + +struct not_fwd_iterable_3 { + typedef int value_type; + bool begin(); + bool size(); +}; + +BOOST_AUTO_TEST_CASE( test_forward_iterable_concept ) +{ + { + typedef std::vector type; + BOOST_CHECK_MESSAGE(boost::unit_test::ut_detail::has_member_size::value, "has_member_size failed"); + BOOST_CHECK_MESSAGE(boost::unit_test::ut_detail::has_member_begin::value, "has_member_begin failed"); + BOOST_CHECK_MESSAGE(boost::unit_test::is_forward_iterable< type >::value, "is_forward_iterable failed"); + } + + { + typedef std::list type; + BOOST_CHECK_MESSAGE(boost::unit_test::ut_detail::has_member_size::value, "has_member_size failed"); + BOOST_CHECK_MESSAGE(boost::unit_test::ut_detail::has_member_begin::value, "has_member_begin failed"); + BOOST_CHECK_MESSAGE(boost::unit_test::is_forward_iterable< type >::value, "is_forward_iterable failed"); + } + + { + typedef std::map type; + BOOST_CHECK_MESSAGE(boost::unit_test::ut_detail::has_member_size::value, "has_member_size failed"); + BOOST_CHECK_MESSAGE(boost::unit_test::ut_detail::has_member_begin::value, "has_member_begin failed"); + BOOST_CHECK_MESSAGE(boost::unit_test::is_forward_iterable< type >::value, "is_forward_iterable failed"); + } + + { + typedef std::set type; + BOOST_CHECK_MESSAGE(boost::unit_test::ut_detail::has_member_size::value, "has_member_size failed"); + BOOST_CHECK_MESSAGE(boost::unit_test::ut_detail::has_member_begin::value, "has_member_begin failed"); + BOOST_CHECK_MESSAGE(boost::unit_test::is_forward_iterable< type >::value, "is_forward_iterable failed"); + } + + + { + typedef float type; + BOOST_CHECK_MESSAGE(!boost::unit_test::ut_detail::has_member_size::value, "has_member_size failed"); + BOOST_CHECK_MESSAGE(!boost::unit_test::ut_detail::has_member_begin::value, "has_member_begin failed"); + BOOST_CHECK_MESSAGE(!boost::unit_test::is_forward_iterable< type >::value, "is_forward_iterable failed"); + } + + { + typedef not_fwd_iterable_1 type; + BOOST_CHECK_MESSAGE(boost::unit_test::ut_detail::has_member_size::value, "has_member_size failed"); + BOOST_CHECK_MESSAGE(!boost::unit_test::ut_detail::has_member_begin::value, "has_member_begin failed"); + BOOST_CHECK_MESSAGE(!boost::unit_test::is_forward_iterable< type >::value, "is_forward_iterable failed"); + } + + { + typedef not_fwd_iterable_2 type; + BOOST_CHECK_MESSAGE(!boost::unit_test::ut_detail::has_member_size::value, "has_member_size failed"); + BOOST_CHECK_MESSAGE(boost::unit_test::ut_detail::has_member_begin::value, "has_member_begin failed"); + BOOST_CHECK_MESSAGE(!boost::unit_test::is_forward_iterable< type >::value, "is_forward_iterable failed"); + } + + { + typedef not_fwd_iterable_3 type; + BOOST_CHECK_MESSAGE(boost::unit_test::ut_detail::has_member_size::value, "has_member_size failed"); + BOOST_CHECK_MESSAGE(boost::unit_test::ut_detail::has_member_begin::value, "has_member_begin failed"); + BOOST_CHECK_MESSAGE(!boost::unit_test::is_forward_iterable< type >::value, "is_forward_iterable failed"); + } + + { + typedef char type; + BOOST_CHECK_MESSAGE(!boost::unit_test::ut_detail::has_member_size::value, "has_member_size failed"); + BOOST_CHECK_MESSAGE(!boost::unit_test::ut_detail::has_member_begin::value, "has_member_begin failed"); + BOOST_CHECK_MESSAGE(!boost::unit_test::is_forward_iterable< type >::value, "is_forward_iterable failed"); + } + + +} +#endif + + + BOOST_AUTO_TEST_CASE( test_basic_value_expression_construction ) { using namespace boost::test_tools;