compile-time cost of alias templates

Gabriel Dos Reis gdr@integrable-solutions.net
Sun Dec 18 23:35:00 GMT 2011


On Sun, Dec 18, 2011 at 5:10 PM, Jonathan Wakely <jwakely.gcc@gmail.com> wrote:
> On 18 December 2011 22:41, Gabriel Dos Reis wrote:
>> On Sun, Dec 18, 2011 at 11:38 AM, Jason Merrill <jason@redhat.com> wrote:
>>> On 12/18/2011 11:00 AM, Jonathan Wakely wrote:
>>>>
>>>> Currently in<functional>  we have this helper class to constrain the
>>>> std::bind function template via SFINAE:
>>>>
>>>>   template<typename _Tp>
>>>>     class __is_socketlike
>>>>     {
>>>>       typedef typename decay<_Tp>::type _Tp2;
>>>>     public:
>>>>       static const bool value =
>>>>         is_integral<_Tp2>::value || is_enum<_Tp2>::value;
>>>>     };
>>>>
>>>> I was going to replace the static member with:
>>>>       static const bool value = __or_<is_integral<_Tp2>,
>>>> is_enum<_Tp2>>::value;
>>>>
>>>> But now that we have alias templates I'm wondering if it would be
>>>> better to write it as:
>>>>
>>>>   template<typename _Tp>
>>>>     using __is_socketlike
>>>>       = __or_<is_integral<typename decay<_Tp>::type>,
>>>>               is_enum<typename decay<_Tp>::type>>;
>>>>
>>>>
>>>> Does the implementation in G++ mean that using an alias template
>>>> avoids instantiating the separate __is_socketlike class template, or
>>>> is there just as much cost in instantiating an alias template as a
>>>> class template?
>>>
>>>
>>> Instantiating an alias is simpler, aliases are basically transparent.
>>
>> Yes; at some point we are planning to publish "memory usage" numbers
>> based on existing practice.
>
> That will be very interesting.
>
>>> However, this change would mean that any mangling exposure of
>>> __is_socketlike would change.  But that may not be an issue since it's an
>>> internal type.
>>>
>>> Jason
>>
>> Agreed.
>> Jonathan, note however that neither the original code nor the new version does
>> short-circuiting of instantiations.
>
> The original code using || (i.e. whats currently used in libstdc++)
> instantiates is_enum<_Tp2> unconditionally.  The version above using
> __or_ avoids that instantiation when is_integral<Tp2> is true, and
> from my brief experiments the alias template appears to avoid
> instantiating it too - am I missing something?

I was looking at this version from your previous message

   template<typename _Tp>
     using __is_socketlike
       = __or_<is_integral<typename decay<_Tp>::type>,
               is_enum<typename decay<_Tp>::type>>;

and was confused by the fact that only decay<_Tp>::type is
unconditionally instantiated, not the rest.  So, no, you are not
missing anything; I was confused by the nesting brackets.


>
> I did see the ext reflector discussion about alias templates not doing
> "lazy" instantiations when used in certain ways, but I don't think
> that's relevant here because I don't refer to a member of is_integral
> or is_enum within the alias template:
>
> template<typename _Tp, typename _Tp2 = typename decay<_Tp>::type>
>   using __is_socketlike = __or_<is_integral<_Tp2>, is_enum<_Tp2>>;

yes, you are fine.  Sorry for the false alarm.

> I'm not really concerned about an extra instantiation of is_enum as
> that's a very small template, but it's good to know that alias
> templates are transparent and simpler. I've found a few good uses for
> them already.

Yes, Dodji's implementation is very close to the spirit of the original
design.  The only one thing that remains (unrelated to your issue)
is the handling of template argument packs whose semantics evolved
over time.  It would be "nice" if we can find a solution that back-propagates
template argument list number constraint so that everything is "just fine".



More information about the Libstdc++ mailing list