专业编程基础技术教程

网站首页 > 基础教程 正文

C++20 新特性(8):range形式的for语句改进

ccvgpt 2024-10-19 03:27:56 基础教程 6 ℃

C++ 11 中新增了range方式的for语句,对于遍历数组、容器等对象时提供了更便利的语法描述,C++ 20对range形式的for语句进行了改进,在讨论具体改进前,先回顾一下 C++ 11 定义的range形式的for语句。

range形式的for语句基础

C++ 11 定义的range形式的for语句的具体语法如下:

C++20 新特性(8):range形式的for语句改进

for ( range_declaration : range_expression ) loop_statement

其中的 range_expression 是一个表达式,执行结果是一个序列,可以是一个数组,或者是一个类的对象实例,这个对象有 begin() 和 end() 方法(可以是类成员变量,或者是独立的函数)。而 range_declaration 是定义一个变量,类型是序列的单个成员。

然后在for循环的每一次遍历中,range_declaration 都指向序列的下一个值,然后在循环体 loop_statement 中,可以使用这个值进行运算。

例如下面的代码:

vector<int> v1 = { 1, 2, 3, 4 };
for( const auto & v : v1 ) {
    cout << v << endl;
}

相当于:

vector<int> v1 = { 1, 2, 3, 4 };
for( auto pv = v1.begin(); pv != v1.end(); ++pv ) {
    auto v = *pv;
    cout << v << endl;
}

使用range形式,能够自动选择遍历数组,还是调用成员函数begin()和end(),还是调用独立的函数begin()和end(),这样对于模板推导时,更加简便。

C++20对range形式for语句的改进(1):增加初始化语句

首先,C++20对range形式的for语句,增加了初始化语句,支持在初始化语句中定义变量,这个变量的生命周期只在for语句内,但是对每次for循环都保持有效,同时也不会影响到for语句外面。

class SA
{
public:
    std::vector< int > & Items() { return m_data; }
private:
    std::vector< int > m_data { 1, 2, 3, 4 };
};
SA func() { return SA{}; }

// <1> 错误代码,func()产生的临时对象会提前被释放,未定义行为
for( auto x : func().Items() ) {   
    cout << x << endl;
}

// <2> 在for外面定义变量,在for整个循环过程都有效,保证for循环的正确性
// 但for循环之后还有效,可能生命周期过长超出期望,除非再加一个大括号来限定
SA a1 = func();  
for( auto x : a1.Items() ) {
    cout << x << endl;
}

// <3> C++ 20 新增语法,支持在range形式的for语句中增加初始化语句
// a2定义的变量不会提前释放,保证了for循环的正确性,同时生命周期也限定在for循环之内
for( SA a2 = func(); auto x : a2.Items() ) {  // <3>
    cout << x << endl;
}

C++20对range形式for语句的改进(2):优化对begin()/end()的查找

C++17中,对于一个类,如果本身只有一个名为begin()或者end()的成员函数,不是成对,此时是无法用在range形式的for语句中的,即使额外定义独立的begin()和end()函数也无济于事。

C++20中,对这种情况进行了改进,要求类成员函数同时有begin()和end()函数时,才会使用类成员函数,否则还是会去继续去找独立的begin()和end()函数,这样就不会被类本身的单个函数所影响。

class SA
{
public:
    // <1> 不成对的 end() 函数,C++17会使用这个,但缺少begin()函数因此出错
    //    但 C++ 20改进之后,会跳过这个不成对的end()函数,继续进行查找
    std::vector< int >::iterator end() { return m_data2.end(); }  
private:
    friend std::vector< int >::iterator begin( SA & a );
    friend std::vector< int >::iterator end( SA & a );
    std::vector< int > m_data { 5, 6, 7, 8 };
    std::vector< int > m_data2 { 1, 2, 3, 4 };
};

// <2> C++ 20中会查找到这两个成对的 begin() 和 end() 函数,支持用来对SA类实例进行遍历
std::vector< int >::iterator begin( SA & a ) { return a.m_data.begin(); }
std::vector< int >::iterator end( SA & a ) { return a.m_data.end(); }

for( SA a; auto x : a ) {
    cout << x << endl;
}


【往期回顾】

C++20 新特性(7):结构化绑定的改进

C++20 新特性(6):new表达式也支持数组大小推导

Tags:

最近发表
标签列表