我正在尝试迭代多个var temp = new MyClass[]
{
new MyClass { Name = "object1", Array = new int[] { 1, 2, 3 } },
new MyClass { Name = "object2", Array = new int[] { 1, 2 } },
new MyClass { Name = "object3", Array = new int[] { 1, 2 } },
new MyClass { Name = "object4", Array =null }
};
var result = temp.GroupBy(i => i.Array, new ArrayComparer()).ToList();
//Now you have 3 groups
,对每个std::list
进行排序。这是天真的方法:
#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.
我是否正确地猜测大括号初始化程序正在创建这些列表的副本?有没有办法不复制它们,并使它们在循环中可修改? (除了制作指向它们的指针列表,这是我当前的解决方法)。
答案 0 :(得分:23)
你猜对了。 std::initializer_list
元素始终为const
(这使sort()
不可能,因为sort()
是非const
成员函数,并且其元素始终被复制(这会使sort()
- 即使它们不是const
,也毫无意义。来自[dcl.init.list],强调我的:
类型为
std::initializer_list<E>
的对象是从初始化列表构造的,就像实现一样 分配了一个N个元素的临时数组,类型为 const E ,其中N是元素的数量 初始化列表。该数组的每个元素都使用初始化程序的相应元素进行复制初始化 列表,构造std::initializer_list<E>
对象以引用该数组。 [注意:一个构造函数 或者,在初始化程序的上下文中,可以访问为副本选择的转换函数(第11条) 名单。 -end note] 如果需要缩小转换来初始化任何元素,程序是 病态的。 [例如:struct X { X(std::initializer_list<double> v); }; X x{ 1,2,3 };
初始化将以与此大致相同的方式实现:
const double __a[3] = {double{1}, double{2}, double{3}}; X x(std::initializer_list<double>(__a, __a+3));
假设实现可以使用一对指针构造
initializer_list
对象。 末端 例子]
无法使它们成为非常量或非复制的。指针解决方案有效:
for (auto l : {&a, &b, &c}) l->sort();
因为它是指针是const,而不是它指向的元素。另一种选择是编写一个可变参数函数模板:
template <typename... Lists>
void sortAll(Lists&&... lists) {
using expander = int[];
expander{0, (void(lists.sort()), 0)...};
}
sortAll(a, b, c);
我猜你也可以写一个帮助器将你的列表包装成reference_wrapper
到list<int>
的数组(因为你不能有一个引用数组),但这可能更多令人困惑而不是有用:
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()
答案 1 :(得分:7)
可以编写一个允许您执行此操作的函数ref_range
:
for(auto& l : ref_range(a,b,c)) {
l.sort();
}
正如其他人所说,一旦你写{a,b,c}
,你就会被initializer_list
所困,而这样的列表总是会复制其参数。副本为const
(因此您的错误),但即使您可以获得非const
引用,您也会修改a
,b
和{{ 1}}而不是原件。
无论如何,这里是c
。它构建ref_range
vector
。{/ p>
reference_wrapper
答案 2 :(得分:2)
{...}
语法实际上是在创建std::initializer_list
。如链接页面所述:
在以下情况下自动构建
std::initializer_list
对象:
- [...]
- braced-init-list 绑定到
auto
,包括在一个范围内的for循环中
并且:
std::initializer_list<T>
类型的对象是一个轻量级代理对象,它提供对const T
类型对象数组的访问。
因此,您无法修改通过此initialize_list
访问的对象。使用指针的解决方案看起来对我来说是最简单的。
答案 3 :(得分:2)
直接回答您的问题:
我是否正确地猜测大括号初始化程序正在创建副本 那些名单?
是的,这是第一个问题。您的代码将创建列表的副本,对这些副本进行排序,最后忘记已排序的副本。
然而,仅此一项就会导致无效的代码。编译器错误提示第二个问题:隐式类型l
是list<int> const&
,而不是list<int>&
。所以编译器抱怨sort()
试图修改常量列表。
您可以使用讨厌的const_cast
:
#include <list>
#include <iostream>
using namespace std;
int main(void){
list<int> a,b,c;
a.push_back(2);
a.push_back(0);
a.push_back(1);
for(auto& l:{a,b,c}) const_cast<list<int>&>(l).sort();
for(auto i:a) cout << i << endl;
}
然而,这将触发第一个问题:您的列表列表包含副本,并且只对这些副本进行排序。所以最终输出不是你想要的:
2
0
1
最简单的解决方法是创建指向列表的指针列表:
#include <list>
#include <iostream>
using namespace std;
int main(void){
list<int> a,b,c;
a.push_back(2);
a.push_back(0);
a.push_back(1);
for(auto l:{&a,&b,&c}) l->sort();
for(auto i:a) cout << i << endl;
}
这将产生所需的结果:
0
1
2
答案 4 :(得分:0)
其他人已经提到了 ffmpeg-N-*
,但他们随后使用它来创建 STL 容器,而不是坚持使用大括号初始化器列表。
所以你需要做的就是:
std::reference_wrapper
当然,这与已经提出的指针解决方案非常相似。