Как работает имплементация для std :: is_function в libcxx? - PullRequest
4 голосов
/ 21 октября 2019

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

Я получил общее представление. Если тип не соответствует ни одному из нефункционального типа (класс, объединение, 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 всегда ложно.

Но я должен ошибиться. Кто-нибудь может указать мне?

1 Ответ

4 голосов
/ 21 октября 2019

Каждый тип в C ++ попадает точно в одну из следующих категорий, возможно, cv-квалифицированных:

  • void
  • decltype(nullptr) (он же std::nullptr_t)
  • Арифметика
  • Массив
  • Указатель ( т.е. , T* для некоторого типа T)
  • Ссылка (lvalue или rvalue)
  • Указатель на нестатический элемент
  • Перечисление
  • class или struct
  • union
  • Функция

После исключения class, union, void, эталона и std::nullptr_t у нас остаются следующие возможные типы:

  • Арифметика
  • Массив
  • Указатель
  • Указатель на нестатический элемент
  • Перечисление
  • Функция

Остальные эксплойты метапрограммирования шаблонадва факта о типах в этих оставшихся категориях:

  • Если _Tp является отвратительным типом функции , то попытка создать ссылочный тип _Tp& неэффективна,В противном случае _Tp& является корректным.
  • В противном случае тип _Tp может быть преобразован в _Tp* тогда и только тогда, когда _Tp является типом функции, посредством преобразования функции в указатель.

Читателю оставлено упражнение, чтобы определить, почему типы class, union, void, reference и std::nullptr_t должны были быть удалены на более ранней стадии перед этим тестом. будет работать правильно.

...