我已经编写了类似迭代器的类,由于某种原因,它没有通过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
,它将全部正常工作。
范围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
的语法约束。
答案 0 :(得分:2)
对于要在范围v3中为Readable
建模的迭代器,它需要:
operator *
取消引用readable_traits
或具有定义关联值类型的公共成员类型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)进行干净地编译。
在范围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