Instead of defining these in terms of a helper class template and the relatively expensive __remove_cv_t, just declare four explicit specializations of the main template, one for each choice of cv-quals. Tested on x86_64-pc-linux-gnu, does this look OK for trunk? The is_void change alone reduces memory usage for join.cc by almost 1%. libstdc++-v3/ChangeLog: * include/std/type_traits (__is_void_helper): Remove. (is_void): Make the primary template derive from false_type, and define four explicit specializations that derive from true_type. (__is_null_pointer_helper, is_null_pointer): Likewise. --- libstdc++-v3/include/std/type_traits | 48 ++++++++++++++++++---------- 1 file changed, 31 insertions(+), 17 deletions(-) diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits index e4d167939d9..b83e7257a9f 100644 --- a/libstdc++-v3/include/std/type_traits +++ b/libstdc++-v3/include/std/type_traits @@ -289,23 +289,30 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION // __remove_cv_t (std::remove_cv_t for C++11). template<typename _Tp> using __remove_cv_t = typename remove_cv<_Tp>::type; + /// @endcond // Primary type categories. - template<typename> - struct __is_void_helper + /// is_void + template<typename _Tp> + struct is_void : public false_type { }; template<> - struct __is_void_helper<void> + struct is_void<void> : public true_type { }; - /// @endcond - /// is_void - template<typename _Tp> - struct is_void - : public __is_void_helper<__remove_cv_t<_Tp>>::type - { }; + template<> + struct is_void<const void> + : public true_type { }; + + template<> + struct is_void<volatile void> + : public true_type { }; + + template<> + struct is_void<const volatile void> + : public true_type { }; /// @cond undocumented template<typename> @@ -571,19 +578,26 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION #define __cpp_lib_is_null_pointer 201309L - template<typename> - struct __is_null_pointer_helper + /// is_null_pointer (LWG 2247). + template<typename _Tp> + struct is_null_pointer : public false_type { }; template<> - struct __is_null_pointer_helper<std::nullptr_t> + struct is_null_pointer<std::nullptr_t> : public true_type { }; - /// is_null_pointer (LWG 2247). - template<typename _Tp> - struct is_null_pointer - : public __is_null_pointer_helper<__remove_cv_t<_Tp>>::type - { }; + template<> + struct is_null_pointer<const std::nullptr_t> + : public true_type { }; + + template<> + struct is_null_pointer<volatile std::nullptr_t> + : public true_type { }; + + template<> + struct is_null_pointer<const volatile std::nullptr_t> + : public true_type { }; /// __is_nullptr_t (deprecated extension). /// @deprecated Non-standard. Use `is_null_pointer` instead. -- 2.37.3.518.g79f2338b37
Instead of defining is_reference in terms of is_lvalue_reference and is_rvalue_reference, just define it directly. Tested on x86_64-pc-linux-gnu, does this look OK for trunk? This reduces memory usage of join.cc by 1%. libstdc++-v3/ChangeLog: * include/std/type_traits (is_reference): Make the primary template derive from false_type. Define two partial specializations that derive from true_type. --- libstdc++-v3/include/std/type_traits | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits index b83e7257a9f..94e73eafd2f 100644 --- a/libstdc++-v3/include/std/type_traits +++ b/libstdc++-v3/include/std/type_traits @@ -611,8 +611,17 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION /// is_reference template<typename _Tp> struct is_reference - : public __or_<is_lvalue_reference<_Tp>, - is_rvalue_reference<_Tp>>::type + : public false_type + { }; + + template<typename _Tp> + struct is_reference<_Tp&> + : public true_type + { }; + + template<typename _Tp> + struct is_reference<_Tp&&> + : public true_type { }; /// is_arithmetic -- 2.37.3.518.g79f2338b37
On Wed, 7 Sept 2022 at 01:46, Patrick Palka via Libstdc++ <libstdc++@gcc.gnu.org> wrote: > > Instead of defining is_reference in terms of is_lvalue_reference > and is_rvalue_reference, just define it directly. > > Tested on x86_64-pc-linux-gnu, does this look OK for trunk? Yes, thanks (I already did this for the std::is_reference_v variable template, but for some reason left this equivalent change in the local branch where I was doing the traits refactoring). > This reduces memory usage of join.cc by 1%. Now that many of the variable templates have been optimized to avoid instantiating class templates, I wonder if the <ranges> code (and anything else that's only defined for C++17 or later) would benefit from using foo_v<T> && bar_v<T> instead of __and_<foo<T>, bar<T>>. With your improvements to __and_ maybe it doesn't make so much difference. > > libstdc++-v3/ChangeLog: > > * include/std/type_traits (is_reference): Make the primary > template derive from false_type. Define two partial > specializations that derive from true_type. > --- > libstdc++-v3/include/std/type_traits | 13 +++++++++++-- > 1 file changed, 11 insertions(+), 2 deletions(-) > > diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits > index b83e7257a9f..94e73eafd2f 100644 > --- a/libstdc++-v3/include/std/type_traits > +++ b/libstdc++-v3/include/std/type_traits > @@ -611,8 +611,17 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION > /// is_reference > template<typename _Tp> > struct is_reference > - : public __or_<is_lvalue_reference<_Tp>, > - is_rvalue_reference<_Tp>>::type > + : public false_type > + { }; > + > + template<typename _Tp> > + struct is_reference<_Tp&> > + : public true_type > + { }; > + > + template<typename _Tp> > + struct is_reference<_Tp&&> > + : public true_type > { }; > > /// is_arithmetic > -- > 2.37.3.518.g79f2338b37 >
On Wed, 7 Sept 2022 at 01:46, Patrick Palka via Libstdc++ <libstdc++@gcc.gnu.org> wrote: > > Instead of defining these in terms of a helper class template > and the relatively expensive __remove_cv_t, just declare four > explicit specializations of the main template, one for each choice > of cv-quals. > > Tested on x86_64-pc-linux-gnu, does this look OK for trunk? Yes, and we should do the same for is_void_v and is_null_pointer_v. Even though the class templates they instantiate will be cheaper now, they can still avoid any class template instantiation. > The is_void change alone reduces memory usage for join.cc by > almost 1%. Also in my queue of trait refactoring, but I haven't tested if these are worth doing yet: template<typename T> struct is_object : is_const<const T>::type { }; template<> struct is_object<void> : false_type { }; template<> struct is_object<const void> : false_type { }; // and so on for volatile and const volatile And we could define is_object_v as simply is_const_v<const T> && is_void_v<T>. Improving is_object should benefit <ranges> and also the is_scalar change proposed at https://gcc.gnu.org/bugzilla/show_bug.cgi?id=96710#c2