How is std::is_empty<T> implemented in VS2015 (or any compiler)?

谁说胖子不能爱 提交于 2020-01-03 08:08:37

问题


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?


回答1:


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.




回答2:


Also ran across this question and took a look at the gcc 4.8 headers in Ubuntu 14.04. In fact there are a family of them, like __is_empty, __is_pod, __is_polymorphic, etc, used in this way

// /usr/include/c++/4.8/type_traits:516
template<typename _Tp>
struct is_empty
    : public integral_constant<bool, __is_empty(_Tp)>
{};

They seem to work without including any C++ headers. I've tried g++ and clang++ to compile this code

#include <stdio.h>

struct X {};

int main()
{
    printf("%d %d %d\n", __is_empty(X), __is_enum(X), __is_class(X));
    return 0;
}

What I feel uncommon is that they look like functions but actually take a type as argument, instead of an instance (not work if you try X x; __is_empty(x);).



来源:https://stackoverflow.com/questions/35531309/how-is-stdis-emptyt-implemented-in-vs2015-or-any-compiler

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!