【问题标题】:What exactly is the Readable concept in Range v3?Range v3 中的 Readable 概念到底是什么?
【发布时间】:2019-11-10 01:47:57
【问题描述】:

我编写了一个类似迭代器的类,但由于某种原因,它没有通过 Range v3 中定义的 Readable 概念。我不知道为什么,我想看看我到底需要怎么做 修改语法(和语义)以实现概念。

根据 Range 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-Readable?

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

我正在尝试调试为什么我的迭代器无法满足概念(因此被范围 v3 函数拒绝)。请注意,Itstd::vector&lt;bool&gt;::iterator 都可以。


Range 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&lt;It&gt;,从It::value_type 中提取,reference_t&lt;It&gt;It::reference 中提取。

我不知道rvalue_reference_t 是如何推导出来的,也不知道CommonReference 在语法约束方面的含义。

【问题讨论】:

  • 在 static_assert() 中没有引用 It 和 i。
  • @TanveerBadar,已更正。
  • 不知道它是否有帮助,但在 zh.cppreference.com/w/cpp/experimental/ranges/iterator/Readable 中有关于可读概念的第二部分 (ranges::CommonReference)
  • @MartinMorterol,这就是我卡住的地方。我不知道lvalue_reference_t 来自哪里以及CommonReference 部分在实践中的含义。
  • 您可以玩这个玩具示例:godbolt.org/z/yl0YAf,并看到Readable 做对了。如果迭代器不是Readable(例如,不能转换为value_type,在std::find 中使用它会产生编译错误。如果您的迭代器确实适用于标准算法但它不能模拟Readable,请发布最小的例子,以便我们进行调查。

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


【解决方案1】:

对于在 range-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) 编译干净。

在 range-v3 的版本 1 中,Readable 不再是类型,而是可转换为 boolconstexpr 值,因此在这种情况下正确的断言是:

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

value_typeoperator * 返回的值不必相同。但是,它们必须在某种意义上是可相互转换的,算法才能工作。这就是CommonReference 概念发挥作用的地方。这个概念基本上要求两种类型共享一个“公共引用类型”,两者都可以转换为。它本质上委托给common_reference 类型特征,其行为在cppreference 中有详细描述(但是请注意,所描述的内容是针对范围 TS 中的内容,可能与range-v3 库)。

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

#include <range/v3/all.hpp>

template <typename T>
class It
{
private:
  class Proxy
  {
  private:
    T &x;

  public:
    Proxy(T &x_) : x(x_) {}

    operator T &() const { return x; }
  };

public:
  using value_type = T;

private:
  T x;

public:
  Proxy operator *() { return {x}; }
};

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

【讨论】:

  • 是的,我的迭代器有一个value_type,但我无法弄清楚value_typedecltype(*It{})decltype(*iter_move???(It{})) 之间还有其他一些隐含的关系。 (是的,我的迭代器取消引用返回一个类似引用的“代理”)。
  • 请注意:这可能是一个错误const T &amp; operator *() const { return *x; },因为迭代器的常量与指向对象的常量无关。
  • @alfC 我已经改进了示例以表明它甚至可以与存储迭代器一起使用
  • @alfC typename It::value_typedecltype(*declval&lt;It &amp;&gt;()) 有共同的类型吗?
  • 你的意思是他们有一个明确定义的std::common_type&lt;It::value_type, decltype(*declval&lt;It&amp;&gt;())&gt;?不,但是有一个特殊的衰减函数(不幸的是,我显然不允许(由 std)专门化 std::decay),它使 decltype(*declval()) 与 value_type 相同。我应该专攻std::common_type 吗?正如我在我的问题中所展示的,这些类型满足了 CommonReference 概念。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-07-04
  • 1970-01-01
  • 2016-06-07
  • 1970-01-01
  • 2016-12-25
  • 2010-11-24
相关资源
最近更新 更多