Suggestions for convenience aliases in <type_traits>

Daniel Krügler daniel.kruegler@gmail.com
Wed Jun 11 05:53:00 GMT 2014


2014-06-10 13:17 GMT+02:00 Jonathan Wakely <jwakely@redhat.com>:
> On 10/06/14 12:47 +0200, Daniel Krügler wrote:
>>> 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.

[Apologies for my late response, but I was completely bound by other things]

The latter. There is an advantage of the second form, because you
combine it like this

SomeTemplate<__conditional_t_<X, Y, Z>>

this would not necessarily instantiate the __conditional_t_ class
template (but it would for the alias). This situation becomes
relevant, if this

__conditional_t_<X, Y, Z>

is part of a potentially unevaluated part of template parameters.

Essentially the same approach is used in __and:

template<typename _B1, typename _B2>
    struct __and_<_B1, _B2>
    : public conditional<_B1::value, _B2, _B1>::type
    { };

and which is only evaluated, when the __and_ class needs to be instantiated.

> Or do you suggest re-implementing it completely, not re-using
> std::conditional?

No, I thought of reusing 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).

In this example the above change suggestion would not help much.

- Daniel



More information about the Libstdc++ mailing list