2

我正在制作一个简单的、非拥有的数组视图类:

template <typename T>
class array_view {
    T* data_;
    size_t len_;
    // ...
};

我想从具有data()size()成员函数的任何容器构造它,但是 SFINAE-d 正确,只有在它是有效且安全的行为才能实际遍历array_view的情况下才能从某个容器构造。Cdata_

我去了:

template <typename C,
          typename D = decltype(std::declval<C>().data()),
          typename = std::enable_if_t<
              std::is_convertible<D, T*>::value &&
              std::is_same<std::remove_cv_t<T>,
                            std::remove_cv_t<std::remove_pointer_t<D>>>::value>
           >
array_view(C&& container)
: data_(container.data()), len_(container.size())
{ }

这似乎完全不令人满意,我什至不确定它是否正确。我是否正确地包括了所有正确的容器并排除了所有错误的容器?有没有更简单的方法来编写这个要求?

4

1 回答 1

3

如果我们看一下N4512std::experimental::array_view中提出的建议,我们会在表 104 中找到以下要求:Viewable

表达式 返回类型 操作语义

v.size() 可转换为 ptrdiff_t

v.data() 类型 T* 使得 T* is static_cast(v.data()) 指向一个
            隐式转换为 U*,至少为连续序列
            和 is_same_v<remove_cv_t<T>, v.size() 的对象(可能
            remove_cv_t<U>> 为真。cv 限定)类型 remove_cv_t<U>。

也就是说,作者对 使用了基本相同的检查.data(),但为 . 添加了另一个检查.size()

为了通过对U的操作使用指针算术T,类型需要根据 [expr.add]p6相似。为限定转换定义了相似性is_same,这就是为什么检查隐式可转换性然后检查相似性(通过)对于指针运算就足够了。

当然,不能保证操作语义。


在标准库中,唯一连续的容器是std::arraystd::vector。还有std::basic_string一个.data()成员,但std::initializer_list没有,尽管它是连续的。

所有的.data()成员函数都是为每个单独的类指定的,但它们都返回一个实际的指针(没有迭代器,没有代理)。

这意味着目前检查.data()标准库容器是否存在就足够了;您想添加一个可兑换性检查以array_view减少贪婪(例如array_view<int>拒绝 some char* data())。


实现当然可以从接口中移开;您可以使用概念、概念仿真,或者简单地enable_if使用适当的类型函数。例如

template<typename T, typename As,
         typename size_rt = decltype(std::declval<T>().size())
         typename data_rt = decltype(std::declval<T>().data())>
constexpr bool is_viewable =
    std::is_convertible_v<size_rt, std::ptrdiff_t>
    && std::is_convertible_v<data_rt, T*>
    && std::is_same_v<std::remove_cv_t<T>, std::remove_cv_t<data_rt>>;

template <typename C,
          typename = std::enable_if_t<is_viewable<C, T>>
         >
array_view(C&& container)
    : data_(container.data()), len_(container.size())
{ }

是的,这不遵循类型函数的常用技术,但它更短,你明白了。

于 2015-09-25T22:31:15.087 回答