diff --git a/src/util/iterutil.hpp b/src/util/iterutil.hpp index a357b667b488a8796520e70a6e84901f61e65033..685398579a14c32971911087d772182d17b3d12d 100644 --- a/src/util/iterutil.hpp +++ b/src/util/iterutil.hpp @@ -44,7 +44,7 @@ upto(I iter, E end) { } template <typename I, typename E, - typename C = typename common_random_access_iterator<I,E>::type> + typename C = common_random_access_iterator_t<I,E>> enable_if_t<std::is_same<I, E>::value || (has_common_random_access_iterator<I,E>::value && is_forward_iterator<I>::value), diff --git a/src/util/meta.hpp b/src/util/meta.hpp index e45d31604d08b53dea1a722cd329c241ffa4da36..e3d7fc9566a221425bc0d326debaa412a50b16bc 100644 --- a/src/util/meta.hpp +++ b/src/util/meta.hpp @@ -171,13 +171,22 @@ struct common_random_access_iterator< >; }; -template <typename I, typename E, typename = void> -struct has_common_random_access_iterator: public std::false_type {}; +template <typename I, typename E> +using common_random_access_iterator_t = typename common_random_access_iterator<I, E>::type; +// NB: using this version of SFINAE instead of a void default template +// parameter because of a bug in gcc 4.9.3. template <typename I, typename E> -struct has_common_random_access_iterator< - I, E, void_t<typename common_random_access_iterator<I, E>::type> -> : public std::true_type {}; +struct has_common_random_access_iterator { +private: + constexpr static bool test(...) { return false; } + + template <typename U = I> + constexpr static bool test(typename common_random_access_iterator<U, E>::type*) { return true; } + +public: + constexpr static bool value = test(nullptr); +}; diff --git a/tests/unit/test_range.cpp b/tests/unit/test_range.cpp index 5b1d84cb97dd72f0dd0cad36afdc27bc389437a8..118a4dc12393e74b74a62f84eee645d0399a490a 100644 --- a/tests/unit/test_range.cpp +++ b/tests/unit/test_range.cpp @@ -96,33 +96,30 @@ TEST(range, empty) { EXPECT_EQ(0u, empty_range_rr.size()); } -template<typename I, typename E, typename = void> -struct util_distance_enabled : public std::false_type {}; - -// This is the same test for enabling util::distance -template<typename I, typename E> -struct util_distance_enabled< - I, E, util::void_t< - util::enable_if_t< - !util::has_common_random_access_iterator<I, E>::value && - util::is_forward_iterator<I>::value - >>> : public std::true_type {}; - -TEST(range, size) { - static_assert(util_distance_enabled< - typename std::list<int>::iterator, - typename std::list<int>::const_iterator>::value, - "util::distance not enabled"); - static_assert(!util_distance_enabled< - typename std::vector<int>::const_iterator, - typename std::vector<int>::iterator>::value, - "util::distance erroneously enabled"); - static_assert(!util_distance_enabled<int*, int*>::value, - "util::distance erroneously enabled"); - static_assert(!util_distance_enabled<int*, const int*>::value, - "util::distance erroneously enabled"); - static_assert(!util_distance_enabled<const int*, int*>::value, - "util::distance erroneously enabled"); +// This is the same test for enabling the incrementing util::distance +// implementation. +template <typename I, typename E> +constexpr bool uses_incrementing_distance() { + return !util::has_common_random_access_iterator<I, E>::value && + util::is_forward_iterator<I>::value; +} + +TEST(range, size_implementation) { + ASSERT_TRUE((uses_incrementing_distance< + std::list<int>::iterator, + std::list<int>::const_iterator + >())); + + ASSERT_FALSE((uses_incrementing_distance< + std::vector<int>::iterator, + std::vector<int>::const_iterator + >())); + + ASSERT_FALSE((uses_incrementing_distance<int*, int*>())); + + ASSERT_FALSE((uses_incrementing_distance<const int*, int*>())); + + ASSERT_FALSE((uses_incrementing_distance<int*, const int*>())); } TEST(range, input_iterator) { @@ -228,7 +225,7 @@ TYPED_TEST_P(counter_range, size) { auto r = counter{signed_int_type{3}}; auto range = util::make_range(l, r); EXPECT_FALSE(range.empty()); - EXPECT_EQ(6, range.size()); + EXPECT_EQ(6u, range.size()); }