RFR: 8251274: Provide utility types for function SFINAE using extra template parameters

Kim Barrett kim.barrett at oracle.com
Thu Aug 27 05:40:14 UTC 2020


> On Aug 26, 2020, at 11:42 AM, Erik Österlund <erik.osterlund at oracle.com> wrote:
> 
> Hi Kim,
> 
> I have one comment on this. IMO using value or type based SFINAE is mostly a matter of preference. Either you prefer passing in trait types, or you prefer passing in constexpr booleans. The constexpr boolean approach seems to be strictly more useful IMO, because you can pass in evaluated constexpr functions, which is simply not possible in type based SFINAE. I have for example a situation where I have VM_Version support for a feature being returned in a constexpr function, that I can use to SFINAE away platform code on unsupported platforms (actual use case for me).

IIt's easy to bounce back and forth using things like std::integral_constant.
(One could even go the route of Boost.Hana for that sort of thing. But I
don't think we are likely to be doing enough metaprogramming to make
implementing that level of infrastructure worthwhile.) So I dispute the
suggestion that one is more useful than the other.

> Therefore, instead of having both EnableIfX and EnableIfT, I wonder if we could just stick to one convention instead, and say we pass in booleans, not types wrapping booleans. That way, there will never be any question as to which convention is being used or which one you should use - we use only one, and simply convert types to booleans before passing in to EnableIf. And then we don't need to have multiple EnableIf macros to differentiate the two cases. We just stick to one by convention and say this is the way we do things. Today we do not to my knowledge use any type SFINAE in HotSpot, it's all value based (the parameter to EnableIf is a bool, not a type). So it would further more seem that is the convention we already have today, and I think is the convention we want to keep on using, especially due to constexpr making that choice strictly more useful.

We could do that. Indeed, the Standard only provides std::enable_if (and
friends) that takes a bool condition.

However, I think type-based SFINAE is common and likely to remain so because
that's the form the type traits currently come in. (Though C++17 adds
template variables for most or all of the trait types. We could perhaps
provide our own until we can use C++17.)

I find the frequent `::value` suffixes intrusive and annoying. (The
alternative of constructing the trait type is perhaps less annoying, i.e.
EnableIfX<std::is_integral<T>()>. Maybe that's good enough. It's also the
same number of characters as the C++17 template variables, though less
useful for additional calculations (unless going Boost.Hana style).)

As I hinted in the RFR email, I tried to have one EnableIf-style API that
handles an argument that can be either a trait type or a constexpr bool
value. Something like

  template<typename T, ENABLE_IF(std::is_integral<T>)>
  void foo(T x) { ... }

  template<typename T1, typename T2, ENABLE_IF(sizeof(T1) == sizeof(T2))>
  void foo(T1 x, T2 y) { ... }

Unfortunately, all my attempts at that tripped over MSVC bugs. And my bug
report was closed as won't fix.

(gcc and clang worked fine for the most part. One of the many variants I
tried (while failing to get past MSVC) ICE'd gcc, which I reported and was
accepted as an ice-on-valid-code regression.)

> So basically, my feedback is that I think you can safely remove EnableIfT and rename EnableIfX to EnableIf instead.

Not while we still have (currently ~100) uses of our (perhaps legacy)
EnableIf, which is significantly different. I'm not interested in developing
or reviewing a change of all the existing EnableIf for function templates to
use the new additional template parameter mechanism in one changeset.



More information about the hotspot-dev mailing list