From 46be68fda3c8dc5a5d19cbdae2061ef1018b8045 Mon Sep 17 00:00:00 2001 From: Sam Yates <halfflat@gmail.com> Date: Tue, 6 Sep 2016 14:46:58 +0200 Subject: [PATCH] Workaround: type member test failure in gcc 4.9.3 Void default argument SFINAE test for presence of type definition within in a class fails in gcc 4.9.3. This commit uses a different SFINAE approach to work around the compiler bug. --- src/util/iterutil.hpp | 2 +- src/util/meta.hpp | 19 ++++++++++---- tests/unit/test_range.cpp | 53 ++++++++++++++++++--------------------- 3 files changed, 40 insertions(+), 34 deletions(-) diff --git a/src/util/iterutil.hpp b/src/util/iterutil.hpp index a357b667..68539857 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 e45d3160..e3d7fc95 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 5b1d84cb..118a4dc1 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()); } -- GitLab