基于无辜范围的循环无效 [英] Innocent range based for loop not working

查看:58
本文介绍了基于无辜范围的循环无效的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

以下内容不会进行编译:

  #include< iostream> 

int main()
{
int a {},b {},c {},d {};

for(auto& s:{a,b,c,d}){
s = 1;
}
std :: cout<< << std :: endl;
返回0;
}

尝试使用Godbolt



编译器错误为:错误:只读引用的分配'



现在在我的实际情况下,列表由类中的成员变量组成。



现在,这不起作用,因为表达式变成了 initializer_list< int> ,实际上复制了a,b,c和d-因此也不允许修改。



我的问题有两个方面:



是否存在不允许以这种方式编写基于范围的for循环的任何动机? 例如。



什么是纠正语法的句法整洁方法是什么?循环的类型?



最好使用以下方式:

  for(auto& s:something(a,b,c,d)){
s = 1;
}

我认为指针间接寻址不是一个好的解决方案(即 {& a,& b,& c,& d} )-在取消迭代器引用时,任何解决方案都应直接提供元素引用

解决方案

根据标准§11.6.4List-initialization / p5 [dcl.init.list] [重点矿井]:


std :: initializer_list类型的对象是根据
初始化程序列表,好像该实现生成并实现了
(7.4)类型为 N const E的数组的prvalue
,其中N是
的数量初始化列表中的元素。该数组的每个元素都使用初始化程序
列表中的相应元素进行
复制初始化,并且构造了std :: initializer_list对象以将该数组引用
。 [注意:为
选择的构造函数或转换函数应在
初始值设定项列表的上下文中可用(第14条)。 —结束注释]如果需要缩小的转换
来初始化任何元素,则该程序格式不正确。


因此,您的编译器在合理地抱怨(即 auto& s 扣除为 int const& s ,您不能

您可以通过引入容器而不是容器来缓解此问题。带有 std :: reference_wrapper的初始值设定项列表(例如 std :: vector):

  #include< iostream> 
#include< vector>
#include< functional>

int main()
{
int a {},b {},c {},d {};

for(auto& s:std :: vector< std :: reference_wrapper< int>> {a,b,c,d}){
s.get()= 1 ;
}
std :: cout<< << std :: endl;
返回0;
}

实时演示


The following does not compile:

#include <iostream>

int main()
{
    int a{},b{},c{},d{};

    for (auto& s : {a, b, c, d}) {
        s = 1;
    }
    std::cout << a << std::endl;
    return 0;
}

Try it on godbolt

Compiler error is: error: assignment of read-only reference 's'

Now in my actual case the list is made of member variables on a class.

Now, this doesn't work because the expression becomes an initializer_list<int> that actually copies a,b,c, and d - hence also not allowing modification.

My question is two-fold:

Is there any motivation behind not allowing to write a range-based for loop in this way ? eg. perhaps there could be a special case for naked brace expressions.

What is a syntactical neat way of fixing this type of loop ?

Something along this line would be preferred:

for (auto& s : something(a, b, c, d)) {
    s = 1;
}

I do not consider pointer indirection a good solution (that is {&a, &b, &c, &d}) - any solution should give the element reference directly when the iterator is de-referenced.

解决方案

According to the standard §11.6.4 List-initialization/p5 [dcl.init.list] [Emphasis Mine]:

An object of type 'std::initializer_list' is constructed from an initializer list as if the implementation generated and materialized (7.4) a prvalue of type "array of N const E", where N is the number of elements in the initializer list. Each element of that array is copy-initialized with the corresponding element of the initializer list, and the std::initializer_list object is constructed to refer to that array. [ Note: A constructor or conversion function selected for the copy shall be accessible (Clause 14) in the context of the initializer list. — end note ] If a narrowing conversion is required to initialize any of the elements, the program is ill-formed.

Thus, your compiler is complaining legitimately (i.e., auto &s deducts to int const& s and you cannot assign to s in the ranged for loop).

You could alleviate this problem by introducing a container instead of an initializer list (e.g., `std::vector’) with ‘std::reference_wrapper’:

#include <iostream>
#include <vector>
#include <functional>

int main()
{
    int a{},b{},c{},d{};

    for (auto& s : std::vector<std::reference_wrapper<int>>{a, b, c, d}) {
        s.get()= 1;
    }
    std::cout << a << std::endl;
    return 0;
}

Live Demo

这篇关于基于无辜范围的循环无效的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆