我想编写一个接受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完整或者错误吗?或者标准库不提供此功能是否有充分的理由?
这里的问题是:您想要的实际约束是什么?
你想要_____吗:
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)
我们真正缺乏的正是这种能力——提取关联类型并直接约束它们。