This implements LWG 2048. We've been shipping a SFINAE-friendly iterator_traits in C++11 mode for years, but this adjusts it to match the form that will be in the next standard i.e. require all the nested members, not only iterator_category.
To implement this I added __void_t, which is identical to the std::void_t that's going into C++17 based on N3911, but we can use it in C++11 mode. I've run a few tests and using __void_t in our _GLIBCXX_HAS_NESTED_TYPE macro reduces the front-end's memory footprint and compile-time compared to the old implementation, so I've altered that. I've also changed a couple of places to use void_t directly instead of using the _GLIBCXX_HAS_NESTED_TYPE macro at all. Tested x86_64-linux, committed to trunk.
commit 57477dc54a9b74a3aaa8d50949d8aa7b23488a4c Author: Jonathan Wakely <jwak...@redhat.com> Date: Tue Nov 11 18:55:33 2014 +0000 Define __void_t and SFINAE-friendly iterator_traits. * include/std/type_traits (__void_t): Define new alias template. (_GLIBCXX_HAS_NESTED_TYPE): Redefine using __void_t. * include/std/functional (_Maybe_get_result_type): Likewise. * include/bits/stl_iterator_base_types.h (__iterator_traits): Likewise. * include/bits/uses_allocator.h (__uses_allocator_helper): Likewise. * testsuite/20_util/bind/ref_neg.cc: Adjust dg-error. * testsuite/20_util/reference_wrapper/typedefs-3.cc: Adjust to changes in _GLIBCXX_HAS_NESTED_TYPE. diff --git a/libstdc++-v3/include/bits/stl_iterator_base_types.h b/libstdc++-v3/include/bits/stl_iterator_base_types.h index bd55987..ba3f923 100644 --- a/libstdc++-v3/include/bits/stl_iterator_base_types.h +++ b/libstdc++-v3/include/bits/stl_iterator_base_types.h @@ -64,7 +64,7 @@ #include <bits/c++config.h> #if __cplusplus >= 201103L -# include <type_traits> // For _GLIBCXX_HAS_NESTED_TYPE, is_convertible +# include <type_traits> // For __void_t, is_convertible #endif namespace std _GLIBCXX_VISIBILITY(default) @@ -138,15 +138,18 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION * provide tighter, more correct semantics. */ #if __cplusplus >= 201103L - -_GLIBCXX_HAS_NESTED_TYPE(iterator_category) - - template<typename _Iterator, - bool = __has_iterator_category<_Iterator>::value> + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 2408. SFINAE-friendly common_type/iterator_traits is missing in C++14 + template<typename _Iterator, typename = __void_t<>> struct __iterator_traits { }; template<typename _Iterator> - struct __iterator_traits<_Iterator, true> + struct __iterator_traits<_Iterator, + __void_t<typename _Iterator::iterator_category, + typename _Iterator::value_type, + typename _Iterator::difference_type, + typename _Iterator::pointer, + typename _Iterator::reference>> { typedef typename _Iterator::iterator_category iterator_category; typedef typename _Iterator::value_type value_type; diff --git a/libstdc++-v3/include/bits/uses_allocator.h b/libstdc++-v3/include/bits/uses_allocator.h index 7281508..a50ce10 100644 --- a/libstdc++-v3/include/bits/uses_allocator.h +++ b/libstdc++-v3/include/bits/uses_allocator.h @@ -40,15 +40,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION constexpr allocator_arg_t allocator_arg = allocator_arg_t(); -_GLIBCXX_HAS_NESTED_TYPE(allocator_type) - - template<typename _Tp, typename _Alloc, - bool = __has_allocator_type<_Tp>::value> + template<typename _Tp, typename _Alloc, typename = __void_t<>> struct __uses_allocator_helper : false_type { }; template<typename _Tp, typename _Alloc> - struct __uses_allocator_helper<_Tp, _Alloc, true> + struct __uses_allocator_helper<_Tp, _Alloc, + __void_t<typename _Tp::allocator_type>> : is_convertible<_Alloc, typename _Tp::allocator_type>::type { }; diff --git a/libstdc++-v3/include/std/functional b/libstdc++-v3/include/std/functional index 92489b7..e711350 100644 --- a/libstdc++-v3/include/std/functional +++ b/libstdc++-v3/include/std/functional @@ -67,24 +67,23 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION _Mem_fn<_Tp _Class::*> mem_fn(_Tp _Class::*) noexcept; -_GLIBCXX_HAS_NESTED_TYPE(result_type) - /// If we have found a result_type, extract it. - template<bool _Has_result_type, typename _Functor> + template<typename _Functor, typename = __void_t<>> struct _Maybe_get_result_type { }; template<typename _Functor> - struct _Maybe_get_result_type<true, _Functor> + struct _Maybe_get_result_type<_Functor, + __void_t<typename _Functor::result_type>> { typedef typename _Functor::result_type result_type; }; /** * Base class for any function object that has a weak result type, as - * defined in 3.3/3 of TR1. + * defined in 20.8.2 [func.require] of C++11. */ template<typename _Functor> struct _Weak_result_type_impl - : _Maybe_get_result_type<__has_result_type<_Functor>::value, _Functor> + : _Maybe_get_result_type<_Functor> { }; /// Retrieve the result type for a function type. diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits index cecc7dc..6b72a3a 100644 --- a/libstdc++-v3/include/std/type_traits +++ b/libstdc++-v3/include/std/type_traits @@ -2404,34 +2404,22 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION using result_of_t = typename result_of<_Tp>::type; #endif + template<typename...> using __void_t = void; + /// @} group metaprogramming - + /** * Use SFINAE to determine if the type _Tp has a publicly-accessible * member type _NTYPE. */ #define _GLIBCXX_HAS_NESTED_TYPE(_NTYPE) \ - template<typename _Tp> \ - class __has_##_NTYPE##_helper \ - { \ - template<typename _Up> \ - struct _Wrap_type \ - { }; \ - \ - template<typename _Up> \ - static true_type __test(_Wrap_type<typename _Up::_NTYPE>*); \ - \ - template<typename _Up> \ - static false_type __test(...); \ - \ - public: \ - typedef decltype(__test<_Tp>(0)) type; \ - }; \ - \ - template<typename _Tp> \ + template<typename _Tp, typename = __void_t<>> \ struct __has_##_NTYPE \ - : public __has_##_NTYPE##_helper \ - <typename remove_cv<_Tp>::type>::type \ + : false_type \ + { }; \ + template<typename _Tp> \ + struct __has_##_NTYPE<_Tp, __void_t<typename _Tp::_NTYPE>> \ + : true_type \ { }; _GLIBCXX_END_NAMESPACE_VERSION diff --git a/libstdc++-v3/testsuite/20_util/bind/ref_neg.cc b/libstdc++-v3/testsuite/20_util/bind/ref_neg.cc index 7810968..fde434f 100644 --- a/libstdc++-v3/testsuite/20_util/bind/ref_neg.cc +++ b/libstdc++-v3/testsuite/20_util/bind/ref_neg.cc @@ -30,10 +30,10 @@ void test01() { const int dummy = 0; std::bind(&inc, _1)(0); // { dg-error "no match" } - // { dg-error "rvalue|const" "" { target *-*-* } 1126 } - // { dg-error "rvalue|const" "" { target *-*-* } 1140 } - // { dg-error "rvalue|const" "" { target *-*-* } 1154 } - // { dg-error "rvalue|const" "" { target *-*-* } 1168 } + // { dg-error "rvalue|const" "" { target *-*-* } 1125 } + // { dg-error "rvalue|const" "" { target *-*-* } 1139 } + // { dg-error "rvalue|const" "" { target *-*-* } 1153 } + // { dg-error "rvalue|const" "" { target *-*-* } 1167 } std::bind(&inc, std::ref(dummy))(); // { dg-error "no match" } } diff --git a/libstdc++-v3/testsuite/20_util/reference_wrapper/typedefs-3.cc b/libstdc++-v3/testsuite/20_util/reference_wrapper/typedefs-3.cc index 7d6a799..909b305 100644 --- a/libstdc++-v3/testsuite/20_util/reference_wrapper/typedefs-3.cc +++ b/libstdc++-v3/testsuite/20_util/reference_wrapper/typedefs-3.cc @@ -46,8 +46,7 @@ struct S012 : S0, S1, S2 { }; using std::true_type; using std::false_type; -using std::integral_constant; -using std::remove_cv; +using std::__void_t; _GLIBCXX_HAS_NESTED_TYPE(argument_type) _GLIBCXX_HAS_NESTED_TYPE(first_argument_type)