英文:
Can i use split_view with a delimiter that's comparable, but otherwise not related to the split range's value type?
问题
std::ranges::split_view
通过将要拆分的范围与分隔符配对来工作。
然而,所述的分隔符以相当奇特的方式定义 - 它需要是一个 forward_range
。
幸运的是,标准允许使用 split_view
,以便传递一个范围和一个单一元素。值得注意的是,这是标准中的一个示例:
string str{"the quick brown fox"};
for (auto word : views::split(str, ' ')) {
cout << string_view(word) << '*';
}
如您所见,我们可以将 ' '
作为分隔符传递。据我所知,这是通过使用以下构造函数实现的:
template<forward_range R>
requires constructible_from<V, views::all_t<R>>
&& constructible_from<Pattern, single_view<range_value_t<R>>>
constexpr explicit split_view(R&& r, range_value_t<R> e);
这允许我们将 std::string
作为范围 R
传递,并将 char
作为分隔符 e
传递。requires
子句通过检查 char
是否是 std::string
的 range_value_t
(它是)以及是否可以创建一个 std::ranges::single_view<char>
来确保这将起作用(可能总是委托给假定分隔符是范围的实现)。效果非常好。
但如果我想要大幅度自定义我的拆分行为怎么办?例如,我想在任何空白字符上拆分。愚蠢的是,我以为这会起作用:
struct Whitespace {
auto operator==(char const c) const noexcept -> bool {
return std::isspace(static_cast<unsigned char>(c));
}
friend auto operator==(char const c, Whitespace const ws) noexcept -> bool {
return ws == c;
}
} whitespace;
auto main() -> int {
auto const text = std::string("3213 421 43 3 532 5 53 53 5 3535 5353");
namespace views = std::ranges::views;
auto numbers = text | views::split(whitespace);
}
但 Whitespace
是既不是范围也不能从中创建 std::ranges::single_view<char>
的类型。即使它是,并且如果可以,也没有办法保留其自定义行为,因为上述构造函数将其转换为普通的 char
。
我是否可以以某种方式使用 std::views::split
以自定义逻辑来拆分,比如 char
范围?
英文:
std::ranges::split_view
works by taking a range that is to be split paired with a delimiter.
However, said delimiter is defined in quite a peculiar way - it needs to be a forward_range
.
Fortunately, the standard allows the usage of split_view
such that a range and a single element is passed. Notably, this is an example from the standard:
string str{"the quick brown fox"};
for (auto word : views::split(str, ' ')) {
cout << string_view(word) << '*';
}
As you can see, we can pass ' '
as a delimiter. To my knowledge, this works by employing the following constructor:
template<forward_range R>
requires constructible_from<V, views::all_t<R>>
&& constructible_from<Pattern, single_view<range_value_t<R>>>
constexpr explicit split_view(R&& r, range_value_t<R> e);
This allows us to pass an std::string
as the range R
and a char
as the delimiter e
. The requires
clause ensures that this will work by checking whether char
is the range_value_t
of an std::string
(it is) and if it's possible to create an std::ranges::single_view<char>
(potentially to always delegate to the implementation that assumes that the delimiter is a range). Works wonders.
But what if I wanted to heavily customize my splitting behavior? For example, I wanted to split on any whitespace. Foolishly, I thought that this will work:
struct Whitespace {
auto operator==(char const c) const noexcept -> bool {
return std::isspace(static_cast<unsigned char>(c));
}
friend auto operator==(char const c, Whitespace const ws) noexcept -> bool {
return ws == c;
}
} whitespace;
auto main() -> int {
auto const text = std::string("3213 421 43 3 532 5 53 53 5 3535 5353");
namespace views = std::ranges::views;
auto numbers = text | views::split(whitespace);
}
But Whitespace
is a type that is neither a range, not you can create an std::ranges::single_view<char>
from it. And even if it was and if you could, there would be no way to retain its custom behaviors, given the fact that the mentioned constructor would convert it to plain, old char
.
Can I somehow use std::views::split
with a custom logic for splitting, let's say, ranges of char
s?
答案1
得分: 0
No. split_view
需要 indirectly_comparable<iterator_t<V>, iterator_t<Pattern>, ranges::equal_to>
,而 ranges::equal_to
需要 equality_comparable_with
(有一个不相关的小细节在这里不相关)。该概念的语义要求不允许非传递的“相等性”(即,t1 == u
,t2 == u
但 t1 != t2
),这对于匹配多个值的任何 u
都是必要的。
因此,所有尝试执行此类操作的都要么是 IFNDR,要么具有未定义的行为。
英文:
No. split_view
requires indirectly_comparable<iterator_t<V>, iterator_t<Pattern>, ranges::equal_to>
, and ranges::equal_to
requires equality_comparable_with
(with an minor caveat not relevant here). The semantic requirements of that concept disallows non-transitive "equality" (i.e., t1 == u
, t2 == u
but t1 != t2
), which is necessary for any u
that matches more than one value.
It follows that all attempts to do such things either are IFNDR or have undefined behavior.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论