RFR (M): 8183927: Hotspot needs C++ type_traits metaprogramming utilities
Erik Österlund
erik.osterlund at oracle.com
Thu Jul 6 13:08:23 UTC 2017
Hi,
I'm sure we have all had moments when we wished we could use the C++11
type_traits header and the nice metaprogramming tools in there, but then
suddenly remembered that we can not, because we are building libjvm.so
with C++03 and are still arguing whether we can use namespaces.
Well.. welcome to the future. I am delighted to announce that now at
least some of those tools will become available.
A bunch of C++11 compliant metaprogramming tools that can be used
already in C++03 have been developed.
They have been developed with the most conservative and portable C++03
code possible so that even exotic compilers can support it.
Special thanks go to Kim Barret whom I have had many long conversations
about many paragraphs of the C++ standard throughout this work. It has
helped a lot and improved the code.
While this change introduces the traits without using it in the code
(more than from gtest), it will become used in already prepared patches
for refactoring Atomic and OrderAccess to use templates rather than hand
picked types like the JNI-specific jint etc types. That serves as the
bottom layer of the upcoming GC barrier interface that also requires
these utilities. Since they are rather large changes, I hope it is okay
that I separate out the metaprogramming utilities. I argue that they are
of value in general in hotspot and will make our lives easier.
All metaprogramming tools have been placed in a new
hotspot/src/share/vm/metaprogramming directory.
Tests have been written and placed in a new test/native/metaprogramming
directory.
A bug ID can be found here:
https://bugs.openjdk.java.net/browse/JDK-8183927
A webrev with code can be found here:
http://cr.openjdk.java.net/~eosterlund/8183927/webrev.00/
Here is a list of metaprogramming tools that have been introduced with a
corresponding short explanation:
============================
template<typename T, T v>
struct IntegralConstant
This metafunction takes as parameters a type and a value.
The type and value can later be queried from the value_type and value
members respectively.
Here is an example usage:
typedef IntegralConstant<bool, true> TrueType;
Now TrueType::value_type is the bool type, and TrueType::value is the
true boolean value.
Many other metafunctions will later inherit from either TrueType or
FalseType to e.g. denote the metafunction returning true or false based
on some condition.
The following traits that start with Is* belong to this category. They
manifest a constant evaluated at compile time that checks some condition
of types.
============================
template <typename X, typename Y>
struct IsSame
This metafunction takes as parameters two types, X and Y, and returns
true iff they are the same type. Otherwise it returns false.
============================
template <typename T>
struct IsConst
This metafunction takes as parameter a type T, and returns true iff T
has a const qualifier in it.
============================
template <typename T>
struct IsVolatile
This metafunction takes as parameter a type T, and returns true iff T
has a volatile qualifier in it.
============================
template<typename T>
struct IsSigned
This metafunction takes as parameter a type T, and checks if it is
signed. This is equivalent to asking std::numeric_limits<>::is_signed,
but additionally disregards CV qualifiers.
============================
template<typename T>
struct IsIntegral
This metafunction takes as parameter a type T, and returns true if it is
an integral type. This is similar to asking
std::numeric_limits<>::is_integer, but additionally disregards CV
qualifiers. Note that this returns false for enums.
============================
template<typename T>
struct IsSignedIntegral
template<typename T>
struct IsUnsignedIntegral
These two metafunctions are helpers that return true for integral types
that have corresponding signedness.
============================
template <typename T>
struct IsFloatingPoint
This metafunction takes as parameter a type T, and returns true iff T is
a floating point type (irrespective of CV qualifiers).
============================
template <typename T>
class IsPointer
This metafunction takes as parameter a type T, and returns true iff T is
a pointer type (irrespective of CV qualifiers).
============================
That is it as far as metafunctions returning booleans go in these
changes. So now we move on to metafunctions that make use of these
boolean conditions.
template <bool condition, typename TrueType, typename FalseType>
struct Conditional
This metafunction constitutes a conditional type, controlled by the
condition passed in. Its type evaluates to TrueType iff the condition is
true, and otherwise evaluates to FalseType.
Here is a contrived toy example:
template<T>
void example(T base) {
typedef Conditional<IsPointer<T>::value, ptrdiff_t, T> ScaleType;
ScaleType offset = offset();
do_something_clever(base + offset);
}
============================
In this example, the type of the offset is ptrdiff_t iff T is a pointer
and otherwise it is T. This allows passing in pointers and integers to
the function, and adding offsets into it.
template <bool B, typename T = void>
struct EnableIf
This metafunction is the key to SFINAE (Substitution Failure Is Not An
Error), a C++ metaprogramming idiom that allows explicitly allowing or
disallowing function overloads based on precise conditions for types
passed in as parameter.
The EnableIf overload guard should replace the return value of a
function. The type T is the type that is intended to be returned if the
overload is allowed based on the passed in condition. By default that is
void.
Here is a contrived toy example usage:
template <typename T>
EnableIf<IsIntegral<T>::value> print(T x) {}
template <typename T>
EnableIf<!IsIntegral<T>::value> print(T x) {}
...
print(1); // calls the first overload enabled for integral types
print("hello SFINAE world"); // call the second overload enabled for
non-integral types
============================
Now we move on to metafunctions that remove properties like e.g. CV
qualifiers, pointers and references from types, resulting in a new type.
template <typename T>
struct RemovePointer
This metafunction takes as parameter a type T, and returns the type
under the pointer iff T is a pointer, and otherwise returns the same type T.
============================
template <typename T>
struct RemoveReference
This metafunction takes as parameter a type T, and returns the type
under the reference iff T is a pointer, and otherwise returns the same
type T.
============================
template <typename T>
struct RemoveCV
This metafunction takes as parameter a type T, and returns the type T
without CV qualifiers.
============================
template <typename T>
struct Decay
This metafunction takes as parameter a type T, and returns the CV
unqualified type under the reference iff T is a reference type, and
otherwise returns the CV unqualified type T.
============================
Testing: A bunch of tests have been added to the
test/native/metaprogramming folder for all traits (except
IntegralConstant, because there is not a whole lot to test there, and it
is used by all condition metafunctions in their corresponding tests).
They have gone through JPRT, and work well on all oracle supported
platforms, and is also known to have recently built with the xlC
compiler on AIX. I would like to ask external maintainers though to
please verify that this works on your compilers. I have done my best to
use the most conservative tricks in the book to make it as portable as
possible, and I hope it will work well for us all.
Thanks,
/Erik
More information about the hotspot-dev
mailing list