我已经编写了类似迭代器的类,由于某种原因,它没有通过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函数拒绝)。注意,
It
和std::vector<bool>::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<It>
提取的It::value_type
和从reference_t<It>
提取的It::reference
。我不知道如何推导
rvalue_reference_t
或CommonReference
在语法约束方面的含义。 最佳答案
为了使迭代器在range-v3中建模Readable
,它需要:
operator *
取消引用readable_traits
的特殊化,或者具有定义关联值类型的公共(public)成员类型value_type
或element_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
不再是类型,而是可转换为constexpr
的bool
值,因此在这种情况下的正确断言应为:static_assert( ranges::Readable<It<int>> );
value_type
和operator *
返回的值不必相同。但是,它们必须在某种意义上可以相互转换,以使算法起作用。这就是CommonReference
概念发挥作用的地方。该概念基本上要求两种类型共享一个“公共(public)引用类型”,并且两种类型都可以转换为该类型。它实质上代表common_reference
类型的traits,其行为在cppreference中进行了详细描述(但是请注意,那里描述的是TS范围内的内容,可能与范围内的内容不完全相同- v3库)。实际上,可以通过以运算符*返回的类型定义转换运算符来满足
Readable
概念。这是一个通过测试(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>>{} );
关于c++ - Range v3中的Readable概念到底是什么?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/56801190/