问题描述
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
来解决此问题。