RFR: 8251274: Provide utility types for function SFINAE using extra template parameters
Erik Österlund
erik.osterlund at oracle.com
Mon Aug 31 08:55:59 UTC 2020
Hi Kim,
On 2020-08-28 21:46, Kim Barrett wrote:
>> On Aug 28, 2020, at 3:44 AM, Erik Österlund <erik.osterlund at oracle.com> wrote:
>>
>> Hi Kim,
>>
>> On 2020-08-27 22:47, Kim Barrett wrote:
>>> That would work, as would a macro that takes a type. That is, both of
>>> these work.
>>>
>>> #define ENABLE_IF_T(...) EnableIfT<__VA_ARGS__> = 0
>>> #define ENABLE_IF_X(...) EnableIfX<__VA_ARGS__> = 0
>>>
>>> I didn't propose either of those because adding a macro just to eliminate
>>> the trailing " = 0" doesn't seem worthwhile.
>> I see. Yeah I can see how that might not feel worthwhile. Although in a way,
>> I guess the macro would hide the implementation details of the enable if mechanism,
>> that otherwise leak out to the enable if user.
>>
>>> I proposed both EnableIfT and EnableIfX because I don't think either alone
>>> is worthwhile, though for different reasons. (Assume that if we only had one
>>> that the T/X suffix would eventually be eliminated.) Both of them are
>>> basically about reducing syntactic noise.
>>>
>>> EnableIfT alone doesn't deal well with expressions, […]
>>>
>>> EnableIfX alone doesn't, in my opinion, carry its weight; just use
>>> std::enable_if_t directly. […]
>>>
>>> I considered not proposing them at all. While I think together they provide
>>> enough to be worth having, I also think that's not blatantly clear and
>>> obvious. A single macro supporting both is much more compelling. If both
>>> were removed, I'm not sure what to do with EnableIfAnd/Or; retain in the
>>> proposal or retract the proposal entirely.
>> I once again understand that having just an alias type for std::enable_if_t
>> that takes an int might not feel worth while.
>>
>> I can't believe I'm about to say this though, but what if you combine the
>> two not worthwhile things into that macro... it just might become worthwhile
>> combined (yes I think I am in favour of the macro while you are not - I don't
>> know what is going on either!).
> What have you done with the real Erik?
What do you mean? Oh and I've started using an IDE with a GUI as well.
Pretty cool that you can click buttons with your mouse like that.
...joking of course!
>> So if we don't do anything, the template parameter SFINAE syntax would seemingly be:
>>
>> template<typename T, std::enable_if_t<std::is_integral<T>::value, int> = 0>
>> void foo (T t) { ... }
>>
>> And if we have an ENABLE_IF macro that takes values only (keeping to the convention
>> we have to work with values only as discussed previously), it would be:
>>
>> template<typename T, ENABLE_IF(std::is_integral<T>::value)>
>> void foo (T t) { ... }
>>
>> Here, I think I would actually prefer using the macro that hides the implementation
>> details how it works from the user, and in the API just focuses on only passing in
>> the right condition. Also, not importantly, the identifier ENABLE_IF is not taken
>> (while EnableIf is). That macro can also have some comments describing the trick
>> at one point, which I think is quite useful on its own.
>>
>> I guess the macro itself would look like this:
>> #define ENABLE_IF(...) std::enable_if_t<__VA_ARGS__ , int> = 0
> The macro needs to be
>
> #define ENABLE_IF(...) std::enable_if_t<(__VA_ARGS__), int> = 0
>
> Otherwise one gets a mess from `ENABLE_IF(sizeof(T) > 4)` for example; the
> angle bracket closes the template parameter list instead of being a greater
> than operator.
Good point.
>> So this value SFINAE only macro for doing SFINAE using a template parameter seems like
>> something that we can actually do without relying on any compiler bugs being fixed or
>> refactoring the world in HotSpot (yet). And I think it is more readable than the return
>> type SFINAE we have today (that requires extra lines for the return type, and you have
>> to scratch your head to figure out what the actual return type is). I would say that
>> such a value SFINAE macro is worthwhile doing, IMO.
> This is the main point of all this, of course. As you know, I really dislike
> the C++98 function template SFINAE syntax. So much so that I'd rather
> delegate to class templates, as was done with the Atomic::*Impl classes. The
> new style enabled by this C++11 feature changes everything. So I'm highly
> motivated to reach some consensus on how we're going to use this new
> feature.
Agreed.
> I think that macro is okay. I would be even happier with it if we had
> variable templates for the type traits, a la C++17, so
>
> std::is_integral<T>::value => std::is_integral_v<T>
>
> We could add a suite of IsIntegralV &etc variable templates. Alternatively,
> I wonder how much trouble we might be taking on if we conditionally defined
> them with something like
>
> #if __cplusplus == 201402L
> namespace std {
> template<typename T> constexpr bool is_integral_v = std::is_integral<T>::value;
> ...
> }
> #endif // __cplusplus
>
> (Note that we can't get *exactly* the behavior of C++17 for these, since
> inline variables are a C++17 language feature. The difference is linkage,
> but I don't expect anyone to care whether `&IsIntegralV<int>` in different
> translation units result in the same address.)
That seems like a good idea. And yeah I really don't think that
difference will matter at all.
>> I tried it in my usecase I mentioned, and I think it looks pretty good. Feels like
>> having a nice comfortable sofa in the sewers. I think I want this nice comfortable sofa.
>>
>> What do you think?
> I had code that used the combined type/value macro and was ready to move forward
> with that until I tried testing with Visual Studio (sigh!). I’d prefer being able to use the
> variable template forms of various traits, but could live without if need be.
>
> If we adopt this macro, I'm inclined to just drop the proposed
> EnableIfAnd<...> and EnableIfOr<…>. I’ve not encountered that many uses for the
> Or case. The And case can be done with separate ENABLE_IF’s, and indeed there
> is a little bit of benefit to doing so, as the compiler may give more helpful error messages
> when trying to figure out why one of the cases failed. (Similar to why it’s better to split
> conjunctive asserts.)
That makes sense. Using the macro and dropping the EnableIf{And | Or}
sounds good to me.
Thanks,
/Erik
More information about the hotspot-dev
mailing list