Skip to content

Commit

Permalink
Fixing decltype problems on Visual 2013
Browse files Browse the repository at this point in the history
  • Loading branch information
raffienficiaud committed Dec 10, 2014
1 parent f94eb54 commit 0871200
Show file tree
Hide file tree
Showing 2 changed files with 147 additions and 22 deletions.
71 changes: 50 additions & 21 deletions include/boost/test/utils/is_forward_iterable.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -65,31 +65,60 @@ struct is_forward_iterable<std::list<T> > : public mpl::true_ {};

namespace ut_detail {

template<typename T>
struct is_present : public mpl::true_ {};

struct is_forward_iterable_impl {
template<typename T>
static typename std::enable_if<
is_present<typename T::const_iterator>::value &&
is_present<typename T::value_type>::value &&
is_present<decltype(boost::declval<T>().size())>::value &&
is_present<decltype(boost::declval<T>().begin())>::value &&
!is_same<typename remove_cv<typename T::value_type>::type,char>::value &&
!is_same<typename remove_cv<typename T::value_type>::type,wchar_t>::value
, mpl::true_>::type
test(int);

template<typename>
static std::false_type test(...);
};

template<typename T>
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 <class T>
struct has_member_size {
private:
struct nil_t;
template<typename T> static auto test(T*) -> decltype( boost::declval<T>().size() );
template<typename> static nil_t test(...);

public:
static bool const value = !std::is_same< decltype(test<T>(nullptr)), nil_t>::value;
};

template <class T>
struct has_member_begin {
private:
struct nil_t;
template<typename T> static auto test(T*) -> decltype( boost::declval<T>().begin() );
template<typename> static nil_t test(...);
public:
static bool const value = !std::is_same< decltype(test<T>(nullptr)), nil_t>::value;

This comment has been minimized.

Copy link
@awulkiew

awulkiew Dec 15, 2014

Member

The use of nullptr breaks the tests on older compilers (e.g. GCC <4.6). The above code should probably be used only if none of the macros below was defined.

BOOST_NO_CXX11_DECLTYPE
BOOST_NO_CXX11_NULLPTR
BOOST_NO_CXX11_TRAILING_RESULT_TYPES

This comment has been minimized.

Copy link
@raffienficiaud

raffienficiaud Dec 15, 2014

Author Member

Thanks,
You mean that gcc<4.6 can handle decltype (BOOST_NO_CXX11_DECLTYPE set to false) but no nullptr? I'll fix that tonight.

Raffi

This comment has been minimized.

Copy link
@awulkiew

awulkiew Dec 15, 2014

Member

Yes, according to https://gcc.gnu.org/projects/cxx0x.html decltype was added in 4.3 but nullptr in 4.6. Since in other compilers the support status might be different it'd probably be the safest to check all C++11 features used in this code fragment.

This comment has been minimized.

Copy link
@raffienficiaud

raffienficiaud Dec 15, 2014

Author Member

I pushed a fix as you suggested. Thanks.

};


template <class T, class enabled = void>
struct is_forward_iterable_impl : std::false_type
{};

template <class T>
struct is_forward_iterable_impl<
T,
typename std::enable_if<
is_present<typename T::const_iterator>::value &&
is_present<typename T::value_type>::value &&
has_member_size<T>::value &&
has_member_begin<T>::value &&
!is_same<typename remove_cv<typename T::value_type>::type,char>::value &&
!is_same<typename remove_cv<typename T::value_type>::type,wchar_t>::value
>::type
> : std::true_type
{};


} // namespace ut_detail

template<typename T>
struct is_forward_iterable {
typedef decltype(ut_detail::is_forward_iterable_impl::test<typename std::remove_reference<T>::type>(0)) type;
enum { value = type::value };
struct is_forward_iterable {
typedef mpl::bool_<ut_detail::is_forward_iterable_impl<T>::value> type;
enum { value = ut_detail::is_forward_iterable_impl<T>::value };
};

#endif
Expand Down
98 changes: 97 additions & 1 deletion test/test_assertion_construction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@

// Boost.Test
#define BOOST_TEST_MODULE Boost.Test assertion consruction test
#include <boost/test/unit_test.hpp>
#include <boost/test/included/unit_test.hpp>
#include <boost/test/tools/assertion.hpp>
#ifdef BOOST_NO_CXX11_AUTO_DECLARATIONS
#include <boost/test/tools/detail/expression_holder.hpp>
Expand All @@ -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<int> type;
BOOST_CHECK_MESSAGE(boost::unit_test::ut_detail::has_member_size<type>::value, "has_member_size failed");
BOOST_CHECK_MESSAGE(boost::unit_test::ut_detail::has_member_begin<type>::value, "has_member_begin failed");
BOOST_CHECK_MESSAGE(boost::unit_test::is_forward_iterable< type >::value, "is_forward_iterable failed");
}

{
typedef std::list<int> type;
BOOST_CHECK_MESSAGE(boost::unit_test::ut_detail::has_member_size<type>::value, "has_member_size failed");
BOOST_CHECK_MESSAGE(boost::unit_test::ut_detail::has_member_begin<type>::value, "has_member_begin failed");
BOOST_CHECK_MESSAGE(boost::unit_test::is_forward_iterable< type >::value, "is_forward_iterable failed");
}

{
typedef std::map<int, int> type;
BOOST_CHECK_MESSAGE(boost::unit_test::ut_detail::has_member_size<type>::value, "has_member_size failed");
BOOST_CHECK_MESSAGE(boost::unit_test::ut_detail::has_member_begin<type>::value, "has_member_begin failed");
BOOST_CHECK_MESSAGE(boost::unit_test::is_forward_iterable< type >::value, "is_forward_iterable failed");
}

{
typedef std::set<int, int> type;
BOOST_CHECK_MESSAGE(boost::unit_test::ut_detail::has_member_size<type>::value, "has_member_size failed");
BOOST_CHECK_MESSAGE(boost::unit_test::ut_detail::has_member_begin<type>::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<type>::value, "has_member_size failed");
BOOST_CHECK_MESSAGE(!boost::unit_test::ut_detail::has_member_begin<type>::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<type>::value, "has_member_size failed");
BOOST_CHECK_MESSAGE(!boost::unit_test::ut_detail::has_member_begin<type>::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<type>::value, "has_member_size failed");
BOOST_CHECK_MESSAGE(boost::unit_test::ut_detail::has_member_begin<type>::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<type>::value, "has_member_size failed");
BOOST_CHECK_MESSAGE(boost::unit_test::ut_detail::has_member_begin<type>::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<type>::value, "has_member_size failed");
BOOST_CHECK_MESSAGE(!boost::unit_test::ut_detail::has_member_begin<type>::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;
Expand Down

0 comments on commit 0871200

Please sign in to comment.