Suggestions for convenience aliases in <type_traits>
Jonathan Wakely
jwakely@redhat.com
Tue Jun 10 11:17:00 GMT 2014
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.
More information about the Libstdc++
mailing list