Reputation: 887
In libcxx/include/type_traits
, std::is_function
is implemented in such a compact way:
namespace __libcpp_is_function_imp
{
struct __dummy_type {};
template <class _Tp> char __test(_Tp*);
template <class _Tp> char __test(__dummy_type);
template <class _Tp> __two __test(...);
template <class _Tp> _Tp& __source(int);
template <class _Tp> __dummy_type __source(...);
}
template <class _Tp, bool = is_class<_Tp>::value ||
is_union<_Tp>::value ||
is_void<_Tp>::value ||
is_reference<_Tp>::value ||
__is_nullptr_t<_Tp>::value >
struct __libcpp_is_function
: public integral_constant<bool,
sizeof(__libcpp_is_function_imp::__test<_Tp>(
__libcpp_is_function_imp::__source<_Tp>(0))) == 1>
{};
template <class _Tp> struct __libcpp_is_function<_Tp, true> : public false_type {};
template <class _Tp> struct _LIBCPP_TEMPLATE_VIS is_function
: public __libcpp_is_function<_Tp> {};
I got the general idea. If a type does not match any of the non-function type (class, union, void, reference, nullptr_t), it is a function type.. However, I can't find the meaning for this line:
sizeof(__libcpp_is_function_imp::__test<_Tp>(__libcpp_is_function_imp::__source<_Tp>(0))) == 1
I think, the result type for __libcpp_is_function_imp::__source<_Tp>(0)
should be _Tp&
. So the result type for __libcpp_is_function_imp::__test<_Tp>(_Tp&)
should be _two
. And sizeof(_two)
should equal to 2, which is different from 1
. In other words, the equation sizeof(__libcpp_is_function_imp::__test<_Tp>(__libcpp_is_function_imp::__source<_Tp>(0))) == 1
is always false.
But I must get something wrong. Could anyone point me out?
Upvotes: 4
Views: 153
Reputation: 119382
Every type in C++ falls into exactly one of the following categories, possibly cv-qualified:
void
decltype(nullptr)
(a.k.a. std::nullptr_t
)T*
for some type T
)class
or struct
union
After eliminating class
, union
, void
, reference, and std::nullptr_t
we are left with the following possible types:
The remaining template metaprogramming exploits two facts about the types in these remaining categories:
_Tp
is an abominable function type, then the attempt to create the reference type _Tp&
is ill-formed. Otherwise, _Tp&
is well-formed._Tp
is convertible to _Tp*
if and only if _Tp
is a function type, via the function-to-pointer conversion.It's left as an exercise for the reader to determine why class
, union
, void
, reference, and std::nullptr_t
types had to be eliminated at an earlier stage before this test would work correctly.
Upvotes: 4