为什么 C++20 范围概念指定了明显误导性的要求?

Fra*_*mes 0 c++ c++-concepts c++20 std-ranges

我正在努力满足我的班级的 C++20 概念。

struct C1
{
    int* begin();
    int* end();
};

static_assert(std::ranges::range<C1>);  // Compiles fine

struct C2 {};

namespace std::ranges    // (A)
{
    auto begin(C2&);
    auto end(C2&);
}

static_assert(std::ranges::range<C2>);  // Fails to compile
Run Code Online (Sandbox Code Playgroud)

std::ranges::range<>概念定义如下:

template <class _Rng>
concept range = requires(_Rng& __r) {
  std::ranges::begin(__r);
  std::ranges::end(__r);
};
Run Code Online (Sandbox Code Playgroud)

从字面意思上看,它指示我声明上面的函数 (A)。但这些都没有帮助。另一方面,像在类中一样定义两个成员函数C1 确实有效。我的问题是,我只是看不到概念所强加的要求与有助于 class 的解决方案之间的语义联系C1。它告诉我做一件事,而实际上我需要做另一件事。

请对此提供一些解释。

背景:在我的生产代码中,我的类确实定义了一个begin()end()函数,每个函数返回一个迭代器。但这个range概念并不满足这些定义,也未能告诉我原因。

请参阅编译器资源管理器上的完整示例

Nic*_*las 8

std::ranges::begin是一个定制点对象;它不是一个可以重载的函数。即使begin是一个正确的函数,您也不能将函数重载插入std命名空间或任何子命名空间(您可以专门化 中的模板std,但前提是它至少涉及一种用户定义的类型)。

遵守的方法std::ranges::begin就是遵守它的规则。在检查给定的范围类型是一个数组(它有专门的逻辑)之后,它将按顺序查找:

  • 返回迭代器的成员begin函数。
  • begin可以通过参数相关的查找(即:)找到的函数,begin(range_object)它返回一个迭代器。

因此,如果您想将类型放入范围而不添加成员,则必须使用后者:将函数begin放在与相关类型相同的命名空间中。此外,它需要返回一个可以验证为迭代器的类型。

  • `ranges::begin` 是在未指定的内联命名空间中定义的,这些定义可以在 `std` 之外共存。 (2认同)