Как работает std::is_convertible::value?

Копался в файлах chromium-a и наткнулся вот на этот

Вот кусочек, в котором происходит какая-то магия.

  template <
      typename U,
      std::enable_if_t<std::is_convertible<U (*)[], T (*)[]>::value>* = nullptr>
  constexpr CheckedContiguousIterator(const CheckedContiguousIterator<U>& other)
      : start_(other.start_), current_(other.current_), end_(other.end_) {
    // We explicitly don't delegate to the 3-argument constructor here. Its
    // CHECKs would be redundant, since we expect |other| to maintain its own
    // invariant. However, DCHECKs never hurt anybody. Presumably.
    DCHECK_LE(other.start_, other.current_);
    DCHECK_LE(other.current_, other.end_);
  }

Объясните, пожалуйста, что происходит вот в этой строке:

template <typename U, std::enable_if_t<std::is_convertible<U (*)[], T (*)[]>::value>* = nullptr>
  • почему " = nullptr"?
  • что такое "U (*)[]" и как оно работает?

Ответы (1 шт):

Автор решения: Alex Guteniev

почему " = nullptr"?

Нипочему. Ну то есть могло бы быть написано по-другому, не меняя сути.

'std::enable_if_t' используется как шаблонный параметр для SFINAE, если подстановка первого параметра для неудачна, 'std::enable_if_t' не скомпилируется и функция выбросится. В случае удачной подстановки, enable_if_t является typedef для своего второго шаблонного параметра, который по умолчанию void. Чтобы в функции не было лишних шаблонных параметров, параметр, образованный enable_if_t делают по умолчанию. Вариантов много:

  • enable_if_t<..., void>* = nullptr - более длинная запись того, что в исходном примере
  • enable_if_t<..., int> = 0 - вариант с шаблонным параметром int
  • class = enable_if_t<...> - вариант с шаблонным параметром типом

что такое "U (*)[]" и как оно работает?

Указатель на массив. По ссылке в комментарии объяснение.

→ Ссылка