Как решить, требуется предложение несовместимо

Я пытаюсь реализовать рекурсивную версиюstd::iter_value_tс концепцией C++20, так что базовый тип Tвложенного контейнера, такого как std::vector<std::vector<...std::vector<T>...>>можно восстановить. Экспериментальная реализация приведена ниже.

      template<typename T>
concept is_iterable = requires(T x)
{
    *std::begin(x);
    std::end(x);
};

template<typename T> requires (!is_iterable<T>)
struct recursive_iter_value_t_detail
{
    typedef typename T type;
};

template<typename T> requires (is_iterable<T>)
struct recursive_iter_value_t_detail
{
    typedef typename std::iter_value_t<typename recursive_iter_value_t_detail<T>::type> type;
};

template<typename T>
using recursive_iter_value_t = typename recursive_iter_value_t_detail<T>::type;

После попытки скомпилировать этот код единственное сообщение об ошибке 'recursive_iter_value_t_detail': requires clause is incompatible with the declarationвыскочило, и я не уверен, что requires clause is incompatible with the declarationзначение. Проблема в том, что структура шаблона не может быть перегружена таким образом? Пожалуйста, помогите мне разобраться в этом.

Ожидаемый результат recursive_iter_value_t<std::vector<std::vector<int>>>является int.

1 ответ

Куча всего.

Во-первых, в C++20 уже есть концепция итерируемости: она называетсяstd::ranges::range.

Во-вторых, начиная с C++11, нет причин использовать typedef. Всегда предпочитаю. Использование typenameтакже был недействителен. Так using type = T;скорее, чем typedef typename T type;Причина этого в том, что usingнамного мощнее (у вас могут быть шаблоны псевдонимов в дополнение к обычным псевдонимам) и что это гораздо более разумный синтаксис (имя, которое вы вводите, находится слева от =а не... практически где угодно).

В-третьих, способ правильно написать частичную специализацию шаблона ограниченного класса состоит в том, что первичный элемент не ограничен:

      template <typename T>
struct recursive_iter_value_t_detail {
    using type = T;
};

а остальные (а) более ограничены, чем первичные, и (б) должны фактически быть специализациями (см. <T>в синтаксисе):

      template <typename T> requires std::ranges::range<T>
struct recursive_iter_value_t_detail<T> {
    // ...
};

Это также может быть написано:

      template <std::ranges::range T>
struct recursive_iter_value_t_detail<T> {
    // ...
};

Наконец, ваш рекурсивный шаг назад. Если это диапазон, вам нужно сначала распаковать диапазон , а затем рекурсивно. В настоящее время вы сначала рекурсируете, но с тем же типом, так что это бесконечная рекурсия. Так должно быть:

      using type = recursive_iter_value_t_detail<std::iter_value_t<T>>::type;

который вы можете написать короче как:

      template <std::ranges::range T>
struct recursive_iter_value_t_detail<T>
    : recursive_iter_value_t_detail<std::iter_value_t<T>>
{ };

В общем, [демо] :

      template<typename T>
struct recursive_iter_value_t_detail
{
    using type = T;
};

template <std::ranges::range T>
struct recursive_iter_value_t_detail<T>
    : recursive_iter_value_t_detail<std::iter_value_t<T>>
{ };

template<typename T>
using recursive_iter_value_t = typename recursive_iter_value_t_detail<T>::type;
Другие вопросы по тегам