My current question has been inspired by attempting to understand how std::unique_ptr<T, D>
utilizes template mechanics to instantiate a template class the size of a T*
when D
(the deleter type) is a lambda function type, but a larger size when D
is a function pointer type (since space needs to be allocated in the unique_ptr
instance to store the function pointer).
Looking through the VS2015 source code, I find that std::unique_ptr
derives from std::_Unique_ptr_base
, which in turn declares a data member of type _Compressed_pair<class _Ty1, class _Ty2, bool = is_empty<_Ty1>::value && !is_final<_Ty1>::value>
. The type _Ty1
in this latter context is the type of the deleter, D
, that is the second unique_ptr
template parameter noted in the previous paragraph; i.e., the motivation behind this question is that I am contrasting _Ty1
being a lambda type, vs. _Ty1
being a function pointer type. (In fact, the default value of the bool
is being utilized.)
I recognize that is_empty<_Ty1>::value
is true
when _Ty1
is an instance of a lambda type (when the lambda has no capture variables and therefore has a 0 size); but that it is false
when _Ty1
is a function pointer type.
This led me to pursue how std::is_empty
is defined.
Ugh!
What follows is the complete implementation of std::is_empty
that I can find in the VS2015 C++ library source code.
In the file type_traits
is this:
// TEMPLATE CLASS is_empty
template<class _Ty>
struct is_empty _IS_EMPTY(_Ty)
{ // determine whether _Ty is an empty class
};
... and the macro _IS_EMPTY
is defined in the same file:
#define _IS_EMPTY(_Ty) \
: _Cat_base<__is_empty(_Ty)>
... and at this point my luck runs dry, because I cannot find the definition of __is_empty
anywhere. I have GREPped through the entire VS2015 installation directory (which includes, I think, all of the C++ library source code, in - though perhaps I'm mistaken).
I like to understand C++ internals when I want to. But ... I'm stuck on this one, and plenty of googling did not reveal the answer (though I have seen reference to intrinsics), and my digging has not ... discovered any source code.
Can someone enlighten this situation? How is std::is_empty<T>
actually implemented in VS2015, or, for that matter, any other compiler?
Looks as if MSVC++ provides an intrinsic __isempty(T)
rather than dealing with a library-level implementation. Since the argument type T
passed to std::is_empty<T>
can be final
, I don't think there can be a safe library implementation and compiler help may be needed.
The only way to determine if a type T
is empty in a library I can think of is this (the specialization deals with non-class
types for which std::is_empty<T>
is not true
):
template <bool, typename T>
struct is_empty_aux: T { unsigned long long dummy; };
template <typename T>
struct is_empty_aux<false, T> { unsigned long long dummy[2]; };
template <typename T>
struct is_empty:
std::integral_constant<bool,
sizeof(is_empty_aux<std::is_class<T>::value, T>)
== sizeof(unsigned long long)> {
};
However, if T
is final
the inheritance in is_empty_aux
is illegal. While the case of a final
class can be detected using std::is_final<T>
I don't see a way to determine whether its objects are empty. Thus, using a compiler intrinsic may be necessary. Compiler intrinsics are certainly necessary for some of the other type traits anyway. Compiler intrinsics are declarations/definitions somehow magically provided by the compiler: they are normally neither explicitly declared nor defined. The compiler has the necessary knowledge about types and exposing this knowledge via intrinsics is a reasonable approach.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With