基于括号的非常量值的基于范围的初始化? [英] Range-based for with brace-initializer over non-const values?

查看:42
本文介绍了基于括号的非常量值的基于范围的初始化?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图遍历多个 std :: list s,并对它们进行排序。这是天真的方法:

I am trying to iterate over a number of std::lists, sorting each of them. This is the naive approach:

#include<list>
using namespace std;
int main(void){
    list<int> a,b,c;
    for(auto& l:{a,b,c}) l.sort();
}

生产

aa.cpp:5:25: error: no matching member function for call to 'sort'
        for(auto& l:{a,b,c}) l.sort();
                             ~~^~~~
/usr/bin/../lib64/gcc/x86_64-linux-gnu/4.9/../../../../include/c++/4.9/bits/stl_list.h:1586:7: note: 
      candidate function not viable: 'this' argument has type 'const
      std::list<int, std::allocator<int> >', but method is not marked const
      sort();
      ^
/usr/bin/../lib64/gcc/x86_64-linux-gnu/4.9/../../../../include/c++/4.9/bits/stl_list.h:1596:9: note: 
      candidate function template not viable: requires 1 argument, but 0 were
      provided
        sort(_StrictWeakOrdering);
        ^
1 error generated.

我正确地猜到了括号初始化器正在创建这些列表的副本吗?有没有办法不复制它们,并使它们在循环内可修改? (除了列出指向它们的指针,这是我当前的解决方法)。

Am I correctly guessing that brace-initializer is creating copy of those lists? And is there a way to not copy them, and make them modifiable inside the loop? (other than making list of pointers to them, which is my current workaround).

推荐答案

您的猜测正确。 std :: initializer_list 元素始终为 const (这使得 sort()使其不可能,因为 sort()是非< const 成员函数),其元素始终复制(这会使 sort()-即使它们不是 const 也使它们毫无意义)。从[dcl.init.list]中,重点突出:

You are guessing correctly. std::initializer_list elements are always const (which makes sort()ing them impossible, as sort() is a non-const member function) and its elements are always copied (which would make sort()-ing them meaningless even if they weren't const). From [dcl.init.list], emphasis mine:


std :: initializer_list< E>类型的对象; 是根据初始化程序列表构造的,就好像实现
分配了N个类型为 const E 的N个元素的临时数组,其中N是
初始化程序列表。该数组的每个元素都用初始化器
列表的对应元素 copy-initialized 进行复制,并且 std :: initializer_list< E> 对象被构造为引用该数组。 [注意:在初始化程序
列表的上下文中,应为副本选择一个构造函数
或转换函数(第11条)。 -尾注] 如果需要缩小转换来初始化任何元素,则该程序是
格式错误。 [示例:

An object of type std::initializer_list<E> is constructed from an initializer list as if the implementation allocated a temporary array of N elements of type 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<E> object is constructed to refer to that array. [ Note: A constructor or conversion function selected for the copy shall be accessible (Clause 11) 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. [ Example:

struct X {
    X(std::initializer_list<double> v);
};
X x{ 1,2,3 };

初始化将以大致等同于以下方式的方式实现:

The initialization will be implemented in a way roughly equivalent to this:

const double __a[3] = {double{1}, double{2}, double{3}};
X x(std::initializer_list<double>(__a, __a+3));

假设实现可以构建 initializer_list 有一对指针的对象。 -结束
的示例]

assuming that the implementation can construct an initializer_list object with a pair of pointers. —end example ]

没有办法使它们成为非常量或非常量-复制。指针解决方案有效:

There is no way to make them non-const or non-copied. The pointer solution works:

for (auto l : {&a, &b, &c}) l->sort();

因为它是常量的 pointer ,而不是它指向的元素。另一种选择是编写可变参数函数模板:

because it's the pointer that's const, not the element it's pointing to. The other alternative would be to write a variadic function template:

template <typename... Lists>
void sortAll(Lists&&... lists) {
    using expander = int[];
    expander{0, (void(lists.sort()), 0)...};
}

sortAll(a, b, c);

我想,您还可以编写一个帮助程序,将您的列表包装到<$ c数组中$ c> reference_wrapper 到 list< int> (因为您不能有多个引用数组),但这可能比帮助更令人困惑:

You could also, I guess, write a helper to wrap your lists into an array of reference_wrapper to list<int> (since you can't have an array of references), but this is probably more confusing than helpful:

template <typename List, typename... Lists>
std::array<std::reference_wrapper<List>, sizeof...(Lists) + 1>
as_array(List& x, Lists&... xs) {
    return {x, xs...}; 
}

for (list<int>& l : as_array(a, b, c)) {  // can't use auto, that deduces
    l.sort();                             // reference_wrapper<list<int>>,
}                                         // so would need l.get().sort()

这篇关于基于括号的非常量值的基于范围的初始化?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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