如何简洁地表达C++20包含T类型值的范围概念?

jrs*_*ala 8 c++ c++20

我想编写一个接受MyType-typed 值范围的函数模板,所以我写了

void f(const std::ranges::range auto& my_range) { /* ... */ }
Run Code Online (Sandbox Code Playgroud)

不幸的是,这并不限制范围内包含的值的类型。requires我可以在函数体块之前使用一个子句,但我想要一些可重用的东西,而不是特定于该函数的。

自然我写了

template <class T, class V>
concept range_of = std::ranges::range<T> && std::is_same_v<V, std::ranges::range_value_t<T>>;

void f(const range_of<MyType> auto& my_range) { /* ... */ }
Run Code Online (Sandbox Code Playgroud)

但令我感到非常惊讶的是,考虑到它看起来多么自然,标准库并不支持开箱即用。这也适用于std::ranges::view我可以写一个类似的view_of概念。

我的定义不range_of完整或者错误吗?或者标准库不提供此功能是否有充分的理由?

Bar*_*rry 4

这里的问题是:您想要的实际约束是什么?

你想要_____吗:

  • 限制范围的值类型具体是T
  • 限制范围的值类型可转换为T?
  • 限制范围的值类型满足其他一些概念,C
  • 以上任何一个,而不是范围的引用类型?

不同的环境需要不同的版本。您的range_of概念是第一个的完美实现(可以使用std::same_as代替,std::is_same_v但并不重要)。但是当你想要别的东西时会发生什么?约束的具体选择很大程度上取决于您想要做什么。

所以直接的答案是:不存在range_of概念,因为对于该概念应该做什么,实际上没有一个真正的答案。


另一个不同的答案是,这甚至没有什么用处。有用的是一种直接的方法来提取给定的关联类型range,以便轻松地对它们添加进一步的约束。

例如,如果我们采用 Rust,我们可以定义一个采用任意迭代器的函数:

fn foo<I: Iterator>(it: I) { ... }
Run Code Online (Sandbox Code Playgroud)

这有点类似于 just void f(range auto)。这是一种限制,但不是很有用。但是Iterator,在 Rust 中,有一个关联类型:its Item。因此,如果您想要Iterator特定类型,那就是:

fn foo<I: Iterator<Item=i32>>(it: I) { ... }
Run Code Online (Sandbox Code Playgroud)

如果您想要一个Iterator其类型满足其他一些约束的类型:

fn foo<T: Debug, I: Iterator<Item=T>>(it: I) { ... }
Run Code Online (Sandbox Code Playgroud)

我们真正缺乏的正是这种能力——提取关联类型并直接约束它们。