我正在使用Concepts TS实现自己的std::span版本。我在执行these constructors时遇到问题:

template<class Container> constexpr span(Container& cont);
template<class Container> constexpr span(const Container& cont);

备注:这些构造函数不得参与重载解析,除非:
  • Container不是span
  • 的特化
  • Container不是array的特化

  • 如何使用概念来实现这一点?

    最佳答案

    首先,创建一个特征以检查特化。 arrayspan在采用类型参数和非类型参数的意义上看起来相同:

    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要求阻止了不错的partial-concept-id语法,但是我可以为此添加另一个概念:
    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)。

    关于c++ - 使用概念禁用类特化,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/54221785/

    10-11 22:41
    查看更多