将 gsl::span 与 range-v3 一起使用

Using gsl::span with range-v3

我尝试了一个小例子来习惯 GSL 和 range-v3 库,我想知道它们如何协同工作。我有这个玩具示例

#include <iostream>
#include <range/v3/all.hpp>

using namespace std;
using namespace ranges;

void example_vector(vector<int> const& v)
{
  ranges::for_each(view::tail(v), [](int x){
    cout << x << ' ';
  });
  cout << '\n';
}

int main()
{
   auto seq = vector<int> { 2,2,2,0,0,2,1,2 };
   example_vector(seq);
}

有效。但是,如果我尝试使用 gsl::span<int> 作为范围,则会导致出现错误消息。编译器告诉我 span 没有满足视图概念。

#include <gsl.h>

// ...

void example_span(gsl::span<const int> v)
{
  ranges::for_each(view::tail(v), [](int x){
    cout << x << ' ';
  });
  cout << '\n';
}

编译器消息:

note: candidate template ignored: disabled by 'enable_if'
      [with Rng = gsl::span<const int, -1> &, Rest = <>, _concept_requires_123 = 42]
                    CONCEPT_REQUIRES_(ViewConcept<Rng, Rest...>())>

但根据我的理解,它应该是因为 span 一个特定的视图,甚至有 begin()end() 迭代器(同类型)。

range-v3 中的 View 概念(以及范围 TS,就此而言)需要类型 R 来满足 Range 概念 -- begin(r)end(r) 界定迭代器范围——以及 Semiregular 概念——R 必须是 copy/move 可构造的 copy/move 可分配的,并且默认可构造的。 Range 的迭代器和标记类型(beginend return)也必须是 Semiregular(除其他要求外)。

span 系列不满足 View 概念,因为 span 在某些情况下不是默认可构造的,并且它们的迭代器在任何情况下都不是默认可构造的。因为即使是标准 C++ 也需要 Forward 迭代器的默认构造,当前 span 迭代器既不符合 Ranges TS、range-v3 也不符合标准 C++。

也就是说,满足所有这些要求系列所必需的更改 are minimal and straight-forward

20161207更新:

range-v3 现在包含 span 的实现,它正确地模拟了 View/Range 概念。

20170128更新:

gsl::span 现在有默认的可构造迭代器。因此,跨度现在可用于 range-v3。具有动态范围的跨度(例如 gsl::span<int>)模拟 RangeView 概念,具有 静态 范围的跨度(例如 gsl::span<int, 42> ) 仅模型 Range,因为它们不符合 View 的默认构造要求。