Range v3中的Readable概念到底是什么?

时间:2019-06-28 05:08:14

标签: c++ c++11 iterator c++-concepts range-v3

我已经编写了类似迭代器的类,由于某种原因,它没有通过Range v3中定义的Readable概念。我不知道为什么,我正在尝试确切地了解我需要 修改语法(和语义)以实现概念。

根据范围v3可读的迭代器的最低语法要求是什么?可以编写一组必须编译的语句吗? (请参见下面的示例)

我有一个迭代器It,我可以使用它进行基本操作(我称之为“可读”),但是它没有通过概念检查:

#include <range/v3/all.hpp>
...
    It i; // ok
    typename It::value_type val = *i; // ok
    typename It::reference ref = *i;   // ok
    typename It::value_type val2{ref}; // ok
    static_assert( ranges::CommonReference<typename It::reference&&, typename It::value_type&>{} ); // ok
    static_assert( ranges::Readable<It>{} ); // error: static assertion failed

我还可以写出哪些其他涉及i的构造来表明It不可读? 换句话说,什么通用代码只能编译并且只有-如果迭代器是Range v3可读的?

在许多地方,它说“如果它的行为像指针,那么它是可读的”,但是我找不到我的迭代器出了什么问题。当我看到需要编译什么代码时,我将能够理解哪里出了问题?

我正在尝试调试为什么我的迭代器无法完成概念(因此被范围v3函数拒绝)。请注意,如果Itstd::vector<bool>::iterator,它将全部正常工作。


范围v3 https://ericniebler.github.io/range-v3/structranges_1_1v3_1_1concepts_1_1_readable.html中的可读概念代码类似于https://en.cppreference.com/w/cpp/experimental/ranges/iterator/Readable

(我使用的版本是0.5.0 [Fedora30])

template < class In >

concept bool Readable =
  requires {
    typename ranges::value_type_t<In>;
    typename ranges::reference_t<In>;
    typename ranges::rvalue_reference_t<In>;
  } &&
  CommonReference<ranges::reference_t<In>&&, ranges::value_type_t<In>&> &&
  CommonReference<ranges::reference_t<In>&&, ranges::rvalue_reference_t<In>&&> &&
  CommonReference<ranges::rvalue_reference_t<In>&&, const ranges::value_type_t<In>&>;

因此,看起来迭代器必须(或可以推论)从value_t<It>提取的It::value_type和从reference_t<It>提取的It::reference

我不知道如何推论rvalue_reference_tCommonReference的语法约束。

1 个答案:

答案 0 :(得分:2)

对于要在范围v3中为Readable建模的迭代器,它需要:

  • 可通过有意义的operator *取消引用
  • 具有专门的readable_traits或具有定义关联值类型的公共成员类型value_typeelement_type

我能想到的最简单的Readable用户定义类型是:

#include <range/v3/all.hpp>

template <typename T>
class It
{
public:
  using value_type = T;

private:
  T x;

public:
  T operator *() const { return x; }
};

static_assert( ranges::Readable<It<int>>{} );

可以使用range-v3版本0.3.5(https://godbolt.org/z/JMkODj)进行干净地编译。

在范围v3的版本1中,Readable不再是类型,而是可转换为constexpr的{​​{1}}值,因此在这种情况下的正确断言将是:

bool

static_assert( ranges::Readable<It<int>> ); value_type返回的值不必相同。但是,它们必须在某种意义上可以相互转换,才能使算法起作用。这就是operator *概念起作用的地方。该概念基本上要求两种类型共享一个“公共引用类型”,并且两种类型都可以转换为该类型。它本质上委托给CommonReference类型的特征,其行为在cppreference中进行了详细描述(但是,请注意,那里描述的是TS范围内的内容,可能不完全相同)与range-v3库相同)。

实际上,可以通过以运算符*返回的类型定义转换运算符来满足common_reference概念。这是一个通过测试(https://godbolt.org/z/5KkNpv)的简单示例:

Readable