libcxx 中 std::is_function 的实现如何工作?
How does the impementation for std::is_function in libcxx work?
在libcxx/include/type_traits
中,std::is_function
是这么紧凑实现的:
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> {};
我大概明白了。 如果类型不匹配任何非函数类型(class、union、void、reference、nullptr_t),则它是函数类型。。但是,我找不到这一行的含义:
sizeof(__libcpp_is_function_imp::__test<_Tp>(__libcpp_is_function_imp::__source<_Tp>(0))) == 1
我想,__libcpp_is_function_imp::__source<_Tp>(0)
的结果类型应该是_Tp&
。所以 __libcpp_is_function_imp::__test<_Tp>(_Tp&)
的结果类型应该是 _two
。而sizeof(_two)
应该等于2,与1
不同。换句话说,等式 sizeof(__libcpp_is_function_imp::__test<_Tp>(__libcpp_is_function_imp::__source<_Tp>(0))) == 1
总是错误的。
但我一定是搞错了。谁能指出我?
C++ 中的每种类型恰好属于以下类别之一,可能是 cv 限定的:
void
decltype(nullptr)
(a.k.a.std::nullptr_t
)
- 算术
- 数组
- 指针(即,对于某些类型
T*
T
)
- 引用(左值或右值)
- 指向非静态成员的指针
- 枚举
class
或 struct
union
- 函数
删除 class
、union
、void
、引用和 std::nullptr_t
后,我们剩下以下可能的类型:
- 算术
- 数组
- 指针
- 指向非静态成员的指针
- 枚举
- 函数
剩余的模板元编程利用了关于这些剩余类别中的类型的两个事实:
- 如果
_Tp
是 abominable function type,则创建引用类型 _Tp&
的尝试格式错误。否则,_Tp&
是合式的。
- 否则,类型
_Tp
可以转换为 _Tp*
当且仅当 _Tp
是一个函数类型,通过函数到指针的转换。
留作 reader 的练习以确定为什么 class
、union
、void
、参考和 std::nullptr_t
类型必须是在该测试正常运行之前的较早阶段被淘汰。
在libcxx/include/type_traits
中,std::is_function
是这么紧凑实现的:
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> {};
我大概明白了。 如果类型不匹配任何非函数类型(class、union、void、reference、nullptr_t),则它是函数类型。。但是,我找不到这一行的含义:
sizeof(__libcpp_is_function_imp::__test<_Tp>(__libcpp_is_function_imp::__source<_Tp>(0))) == 1
我想,__libcpp_is_function_imp::__source<_Tp>(0)
的结果类型应该是_Tp&
。所以 __libcpp_is_function_imp::__test<_Tp>(_Tp&)
的结果类型应该是 _two
。而sizeof(_two)
应该等于2,与1
不同。换句话说,等式 sizeof(__libcpp_is_function_imp::__test<_Tp>(__libcpp_is_function_imp::__source<_Tp>(0))) == 1
总是错误的。
但我一定是搞错了。谁能指出我?
C++ 中的每种类型恰好属于以下类别之一,可能是 cv 限定的:
void
decltype(nullptr)
(a.k.a.std::nullptr_t
)- 算术
- 数组
- 指针(即,对于某些类型
T*
T
) - 引用(左值或右值)
- 指向非静态成员的指针
- 枚举
class
或struct
union
- 函数
删除 class
、union
、void
、引用和 std::nullptr_t
后,我们剩下以下可能的类型:
- 算术
- 数组
- 指针
- 指向非静态成员的指针
- 枚举
- 函数
剩余的模板元编程利用了关于这些剩余类别中的类型的两个事实:
- 如果
_Tp
是 abominable function type,则创建引用类型_Tp&
的尝试格式错误。否则,_Tp&
是合式的。 - 否则,类型
_Tp
可以转换为_Tp*
当且仅当_Tp
是一个函数类型,通过函数到指针的转换。
留作 reader 的练习以确定为什么 class
、union
、void
、参考和 std::nullptr_t
类型必须是在该测试正常运行之前的较早阶段被淘汰。