libcxx中std :: is_function的强制实现如何工作?

时间:2019-10-21 14:52:06

标签: c++ c++11 typetraits libc++

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> {};

我有大致的想法。 如果类型与任何非函数类型(类,联合,无效,引用,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始终为假。

但是我必须弄错了。有人可以指出我吗?

1 个答案:

答案 0 :(得分:4)

C ++中的每种类型都完全属于以下类别之一,可能符合cv要求:

  • void
  • decltype(nullptr)(又称std::nullptr_t
  • 算术
  • 数组
  • 指针(T*用于某些类型T
  • 参考(左值或右值)
  • 指向非静态成员的指针
  • 枚举
  • classstruct
  • union
  • 功能

在消除了classunionvoid,引用和std::nullptr_t之后,我们剩下了以下可能的类型:

  • 算术
  • 数组
  • 指针
  • 指向非静态成员的指针
  • 枚举
  • 功能

剩余的模板元编程利用了关于这些剩余类别中的类型的两个事实:

  • 如果_Tpabominable function type,则创建引用类型_Tp&的尝试格式错误。否则,_Tp&格式正确。
  • 否则,只有并且_Tp是函数类型时,类型_Tp*才能通过函数到指针的转换转换为_Tp

留给读者的练习是确定为什么在更早的阶段之前必须消除classunionvoid,引用和std::nullptr_t类型该测试将正常工作。