Jak*_*ark 8 c++ c++-concepts ranged-loops c++20
有许多不同的方法可以使类型/类在范围 for 循环中可用。例如,在cppreference上给出了概述:
range-expression进行评估以确定要迭代的顺序或范围。序列中的每个元素依次被取消引用,并用于使用范围声明中给定的类型和名称来初始化变量。
begin_expr并end_expr定义如下:
- 如果
range-expression是数组类型的表达式,则begin_expris__range和end_expris (__range+__bound),其中__bound是数组中元素的数量(如果数组大小未知或类型不完整,则程序格式错误)- 如果是同时具有指定成员和指定成员的
range-expression类类型的表达式(无论该成员的类型或可访问性如何),则is且isCbeginendbegin_expr__range.begin()end_expr__range.end()- 否则,
begin_exprisbegin(__range)和end_exprisend(__range),它们是通过参数相关的查找找到的(不执行非 ADL 查找)。
如果我想在函数模板中使用范围 for 循环,我想限制类型在范围 for 循环中可用,以触发编译器错误并显示一条漂亮的“约束不满足”消息。考虑以下示例:
template<typename T>
requires requires (T arg) {
// what to write here ??
}
void f(T arg) {
for ( auto e : arg ) {
}
}
Run Code Online (Sandbox Code Playgroud)
显然,对于通用函数,我想支持上面列出的所有方式,类型可以使用这些方式来使其自身兼容。
这引出了我的问题:
begin,end
无论此类成员的类型或可访问性如何(引用列表中的第二个项目符号)。例如,begin()
如果成员是私有的,则测试成员是否存在的 require 子句将失败begin(),但无论如何,范围 for 循环都可以使用该类型。注意 我知道以下两个问题:
但他们都没有真正回答我的问题。
看起来你需要的是std::ranges::range需要表达式ranges::begin(t)并且格式ranges::end(t)良好。
其中[range.access.begin]ranges::begin中定义:
\n\n该名称
\nranges\xe2\x80\x8b::\xe2\x80\x8bbegin表示自定义点对象。给定一个E类型为 的子表达式T,\n令 t 为表示 的具体化对象的左值E。然后:\n
\n- \n
如果
\nE\n 是一个右值并且enable_\xc2\xadborrowed_\xc2\xadrange<remove_\xc2\xadcv_\xc2\xadt<T>>是false,\nranges\xe2\x80\x8b::\xe2\x80\x8bbegin(E)是格式错误的。- \n
否则,如果
\nT是数组类型并且remove_\xc2\xadall_\xc2\xadextents_\xc2\xadt<T>是不完整类型,则格式ranges\xe2\x80\x8b::\xe2\x80\x8bbegin(E)错误,无需诊断。- \n
否则,如果 T 是数组类型,
\nranges\xe2\x80\x8b::\xe2\x80\x8bbegin(E)则表达式等于t + 0。- \n
否则, if
\nauto(t.begin())是一个\n有效表达式,其类型模型input_\xc2\xador_\xc2\xadoutput_\xc2\xaditerator,\nranges\xe2\x80\x8b::\xe2\x80\x8bbegin(E)与 等价于表达式auto(t.begin())。- \n
否则,if
\nT是一个类或枚举类型,并且auto(begin(t))是\n有效的表达式,input_\xc2\xador_\xc2\xadoutput_\xc2\xaditerator\n其类型模型具有\n在非限定查找\nforbegin仅查找声明的上下文中执行的重载解析Run Code Online (Sandbox Code Playgroud)\nvoid begin(auto&) = delete; \nvoid begin(const auto&) = delete;\nthen
\nranges\xe2\x80\x8b::\xe2\x80\x8bbegin(E)的表达式相当于auto(begin(t))在上述上下文中执行的重载解析。- \n
否则,
\nranges\xe2\x80\x8b::\xe2\x80\x8bbegin(E)格式错误。
也就是说,它不仅会对数组类型进行特定的操作,还会根据表达式的有效性来决定是调用成员函数range.begin()还是自由函数begin(range),这已经涵盖了所谓range-expression所描述的行为。并ranges::end遵循类似的规则。所以我认为你可以简单地做
template<std::ranges::range T>\nvoid f(T arg) {\n for (auto&& e : arg) { // guaranteed to work\n }\n}\nRun Code Online (Sandbox Code Playgroud)\n需要注意的是,ranges::begin要求返回的类型必须是 model input_or_output_iterator,并且ranges::end还要求返回的类型必须是 modelsentinel_for返回的类型ranges::begin,这样就T可以是 a 了range。范围表达式没有这样的约束,它只检查表达式的有效性,因此可以使用基于范围的 for 循环的最小类型可以是
struct I {\n int operator*();\n I& operator++();\n bool operator!=(const I&) const;\n};\n\nstruct R {\n I begin();\n I end();\n};\n\nfor (auto x : R{}) { } // well-formed\nRun Code Online (Sandbox Code Playgroud)\n但我认为您对这种情况不感兴趣,因为I不足以构成有效的迭代器。
| 归档时间: |
|
| 查看次数: |
238 次 |
| 最近记录: |