This is the mail archive of the
libstdc++@gcc.gnu.org
mailing list for the libstdc++ project.
Re: Suggestions for convenience aliases in <type_traits>
- From: Jonathan Wakely <jwakely at redhat dot com>
- To: Daniel Krügler <daniel dot kruegler at gmail dot com>
- Cc: libstdc++ <libstdc++ at gcc dot gnu dot org>
- Date: Tue, 10 Jun 2014 12:17:02 +0100
- Subject: Re: Suggestions for convenience aliases in <type_traits>
- Authentication-results: sourceware.org; auth=none
- References: <20140610103036 dot GI30729 at redhat dot com> <CAGNvRgDWicqfYQfh3L=ubuhnBYbM0G7_+_k5GTwXk6E5VRdbbw at mail dot gmail dot com>
On 10/06/14 12:47 +0200, Daniel Krügler wrote:
2014-06-10 12:30 GMT+02:00 Jonathan Wakely <jwakely@redhat.com>:
One of the reasons I've avoided adding the last two is that I'm not
sure how to name them appropriately.
In Boost.MPL the trait that takes a type parameter as its first
template parameter is named enable_if, and the version taking a
non-type bool parameter is named enable_if_c, but in the std::lib we
dropped the _c suffix.
IMO the comparison with the corresponding boost traits is not a good
one, because alias templates are not evaluated lazily, so
__enable_if_t_ or __conditional_t_ leads to the incorrect assumption
not to evaluate the provided predicate.
OK, avoiding names with misleading implications is important.
The alias templates above are named to be consistent with the similar
C++14 aliases, but with an additional _ suffix, which is consistent
with the invaluable __and_, __or_ and __not_ aliases we already have
in <type_traits> (which also have type parameters not bools).
(I don't know why I wrote that __and_ etc. were aliases there, I know
they're not as they need to be partially specialized ... stupid brain.)
Is that reasonable?
Personally I consider these as bad examples for alias templates and
suggest to provide corresponding class templates instead (such __and,
__or, __not).
Do you mean like this?
template<typename _If, typename _Then, typename _Else>
struct __conditional_
: conditional<_If::value, _Then, _Else>
{ };
With that I lose the convenience of the C++14 '_t' aliases and have to
write 'typename' and '::type' every time I use it.
Or do you mean like this:
template<typename _If, typename _Then, typename _Else>
struct __conditional_t_
: conditional<_If::value, _Then, _Else>::type
{ };
In that case doesn't it also evaluate the prediate immediately, and so
has no advantage over the alias template.
Or do you suggest re-implementing it completely, not re-using
std::conditional?
My use cases for the suggested aliases all involve immediate
evaluation of the predicate anyway, e.g. for <experimental/any>
template<typename _Tp>
struct _Manager_internal;
template<typename _Tp>
struct _Manager_external;
template<typename _Tp, typename _Safe = is_nothrow_copy_constructible<_Tp>,
bool _Fits = (sizeof(_Tp) <= sizeof(_Storage))>
using _Internal = std::integral_constant<bool, _Safe::value && _Fits>;
template<typename _Tp>
using _Manager = conditional_t<_Internal<_Tp>::value,
_Manager_internal<_Tp>,
_Manager_external<_Tp>>;
template<typename _Tp, typename _Decayed = decay_t<_Tp>>
using _Decay = enable_if_t<!is_same<_Decayed, any>::value, _Decayed>;
template <typename _ValueType, typename _Tp = _Decay<_ValueType>,
typename _Mgr = _Manager<_Tp>>
any(_ValueType&& __value);
With the suggested aliases _Internal and _Manager become:
template<typename _Tp, bool _Fits = (sizeof(_Tp) <= sizeof(_Storage))>
using _Internal = __and_<std::__boolean_constant<bool, _Fits>,
is_nothrow_copy_constructible<_Tp>>;
template<typename _Tp>
using _Manager = __conditional_t_<_Internal<_Tp>,
_Manager_internal<_Tp>,
_Manager_external<_Tp>>;
(Those are only slightly simpler, but the difference adds up over many
files to be more significant).
Where conditional<> is used in the constructor I want the predicate to
be evaluated immediately, or am I missing something fundamental about
how aliases interact with SFINAE here?
What would I gain from:
template<typename _Tp>
using _Manager = typename __conditional_<
_Internal<_Tp>, _Manager_internal<_Tp>, _Manager_external<_Tp>
>::type;
?
Thanks for your input.