Использование уровня косвенности в шаблоне ограничение SFINAE вызывает серьезную ошибку - PullRequest
2 голосов
/ 04 мая 2019

В следующем коде (https://wandbox.org/permlink/rA7lnXM6eQR4JhSM)

#include <type_traits>

template <typename T>
struct Identity : public T {};

class Something {
public:
  Something() = default;
  Something(const Something&) = delete;
  Something(Something&&) = default;
  Something& operator=(const Something&) = default;
  Something& operator=(Something&&) = default;

  template <
      typename T,
      typename U = std::decay_t<T>,
      std::enable_if_t<Identity<
        std::is_constructible<U, T&&>>::value>* = nullptr>
  explicit Something(T&&) {};
};

int main() {
    static_cast<void>(std::is_constructible<Something, const Something&>{});
}

я получаю следующую ошибку

error: base class has incomplete type
struct Identity : public T {};
                  ~~~~~~~^

Ошибка исчезает, когда я удаляю косвенное обращение с помощью Identityв ограничении этого (https://wandbox.org/permlink/MFJCHUzeKnS4yR0d)

  template <
      typename T,
      typename U = std::decay_t<T>,
      std::enable_if_t<
        std::is_constructible<U, T&&>::value>* = nullptr>
  explicit Something(T&&) {};

Насколько я понимаю, проблема здесь заключалась в том, что мы пытаемся создать экземпляр std::is_constructible, который затем создает экземпляр конструктора для Something, который затем, в свою очередь,создает экземпляр std::is_constructible и т. д.

Но почему ошибка исчезает, когда я пытаюсь скомпилировать ее без Identity? И почему она выдает ошибку, когда я использую Identity?

1 Ответ

1 голос
/ 04 мая 2019

Вы уже выяснили, что существует «рекурсивная реализация». Там нет реальной рекурсии; что происходит в случае, когда «работает», просто при рассмотрении шаблона конструктора, чтобы выяснить, удастся ли конструкция из const Something&, std::is_constructible<Something, const Something&> не имеет члена value пока . (Вопреки распространенному мнению, класс C не обязательно должен быть полным для именования члена с C:: - но названный член должен быть уже объявлен, и точное значение «уже» является немного мутным .)

Эта ошибка находится в непосредственном контексте шаблона конструктора, поэтому шаблон игнорируется. (Это не имеет значения в этом случае: (удаленный) конструктор копирования является лучшим соответствием, так как это не шаблон.) Это устанавливает, что тот самый value, который отсутствовал, равен false, что по крайней мере соответствует с отклонением шаблона конструктора в первый раз. Это может быть нарушением [meta.rqmts] / 5 для самой специализации std::is_constructible; учтите, что веселье наступает, если мы отрицаем условие в enable_if, которое контролирует себя.

Ваш Identity сталкивается с той же ошибкой (или более общая проблема соответствующей специализации еще не завершена). Являясь частью вспомогательного экземпляра, ошибка неустранима.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...