微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

为什么范围不为非连续范围提供类型擦除视图?

如何解决为什么范围不为非连续范围提供类型擦除视图?

我想要一个函数获取固定值类型的任何范围/视图。

int main()
{
    std::array<std::pair<int,int>,2> a{...};
    std::array<std::pair<int,3> b{...};
    generic_fun(a);
    generic_fun(b);

};

当然可以

template <std::ranges::range R>
    requires std::same_as<std::ranges::range_value_t<R>,std::pair<int,int>>
auto generic_fun(R range)
{
    for(const auto& element : range)
        return element.first;
}

但是 Visual Studio ide 不知道 element 的类型。

我期待范围库具有类似的类型

template <typename T>
struct view
{
    template <std::ranges::range R>
        requires std::same_as<std::ranges::range_value_t<R>,T>
    view(R);
    T* begin() const;
    T* end() const;
};

哪个会给我IDE支持

auto generic_fun(view<std::pair<int,int>> a)
{
    for (const auto& b : a)
        return b.first;
}

为什么 range 库中不存在这样的类型?定义一种抽象出除范围/迭代器的值类型之外的所有类型的类型在技术上是不可行的吗?或者没有人关心这样做,因为唯一的原因是ide支持

我虽然有一个类型(基于给定值类型的模板)包装给定的迭代器概念是很自然的,但 std 没有定义任何。 (如果互联网上有关于包装概念的类型的内容,请您指点一下?)

解决方法

range-v3 将其命名为 any_view<Ref,Cat>,其中 Ref 是范围的 reference(不是 value_type),Cat 是迭代类别(默认为 input)。那会让你写一个像这样的函数:

int sum(any_view<int const&> v) { // <== not a function template
    int s = 0;
    for (int i : v) {
        s += i;
    }
    return s;
}

std::list<int> l = {1,2,3};
assert(sum(l) == 3);

问题是,这个范围适配器非常昂贵。想想迭代的工作方式。我们有一个循环:

for (; it != end; ++it) {
    use(*it);
}

即使对于输入迭代器,这也意味着您必须输入擦除:

  • operator!=
  • operator++
  • operator*

这是三个间接调用每个元素virtual 函数调用,或通过函数指针,取决于实现)。这是一个很大的开销,而且很少有你真正想要使用的东西。因此,将范围适配器添加到 C++20 中的优先级非常低,甚至不在我们未来添加范围适配器的 plan 中。

现在,对于连续范围,情况有点不同,因为您始终可以只存储 (T*,size_t),而原始范围是什么并不重要。它仍然是类型擦除,但它是免费的 - 没有额外的开销。所以 span<T> 在这方面很棒。

或者没有人关心这样做,因为唯一的原因是ide支持?

在某些情况下,类型擦除实际上很重要。也许您正在存储一堆不同类型的范围。也许您将其隐藏在 ABI 边界上。但是 IDE 支持似乎是使用类型擦除的一个非常弱的动力 - 特别是在这样的环境中,这样做会产生相当大的性能开销。

[...] 但是 Visual Studio IDE 不知道 element 的类型。

您也可以通过不使用 auto 来解决此问题。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。