Сначала создайте черту для проверки специализаций. array
и span
выглядят одинаково в том смысле, что они принимают параметр типа и параметр не тип:
template <typename T, template <typename, auto> class Z>
struct is_specialization : std::false_type { };
template <typename A, auto V, template <typename, auto> class Z>
struct is_specialization<Z<A,V>, Z> : std::true_type { };
template <typename T, template <typename, auto> class Z>
inline constexpr bool is_specialization_v = is_specialization<T, Z>::value;
И тогда мы можем построить концепцию из этого:
// the last bullet point
template <typename T, typename E>
concept ValidForElement =
ConvertibleTo<std::remove_pointer_t<T>(*)[], E(*)[]>;
template <typename T, typename E>
concept AllowedContainer =
// not a specialization of span (note: requires forward declaration of span)
!is_specialization_v<std::remove_cv_t<T>, std::span>
// not a specialization of array
&& !is_specialization_v<std::remove_cv_t<T>, std::array>
// not a raw array
&& !std::is_array_v<std::remove_cv_t<T>>
&& requires (T cont) {
// data(cont) is well-formed and has a valid type
{ data(cont); } -> ValidForElement<E>
// size(cont) is well-formed
{ size(cont); }
};
Что бы вы использовали, как:
template <typename Element, std::ptrdiff_t Extent = -1>
struct span {
template <typename C> requires AllowedContainer<C, Element>
span(C&);
template <typename C> requires AllowedContainer<C const, Element>
span(C const&);
};
<час />
Требование const
-ness не позволяет использовать красивый синтаксис частичный-идентификатор-концепции , но мы могли бы просто добавить еще одну концепцию для этого:
template <typename T, typename E>
concept ConstAllowedContainer = AllowedContainer<T const, E>;
template <typename Element, std::ptrdiff_t Extent = -1>
struct span {
template <AllowedContainer<E> C> span(C&);
template <ConstAllowedContainer<E> C> span(C const&);
};
Не уверен, что здесь есть более умный подход.
<час />
Но на самом деле вся эта пара конструкторов, вероятно, является ошибкой, и вы хотите сделать ссылку для пересылки:
template <typename Element, std::ptrdiff_t Extent = -1>
struct span {
template <AllowedContainer<E> C>
span(C&&);
};
Этот последний подход требует нескольких изменений в концепции (все remove_cv_t
должны стать remove_cvref_t
).