我有一些 classFoo
和 astd::list<std::reference_wrapper<Foo>>
并且想使用基于范围的 for 循环迭代它的元素:
#include <list>
#include <functional>
#include <iostream>
class Foo {
public:
Foo(int a) : a(a) {}
int a;
};
int main() {
std::list<Foo> ls = {{1},{2},{3},{4}};
std::list<std::reference_wrapper<Foo>> refs(ls.begin(), std::next(ls.begin(),2));
for(auto &foo : refs) {
std::cout << foo.get().a << std::endl;
}
for(Foo &foo : refs) {
std::cout << foo.a << std::endl;
}
return 0;
}
注意,当我们推断出 typeget()
时,在捕获时附加了额外的内容,而在第二种情况下,当我们显式地捕获此类型时,已经隐式转换为类型。auto
std::reference_wrapper<Foo>
foo
Foo&
我实际上是在寻找一种方法来捕捉 auto 但隐含地抛弃了std::reference_wrapper
隐含的方法,以便不必一直get()
在体内打扰该方法for
,所以我尝试引入一个合适的概念并抓住它,即我尝试了
//this is not legal code
template<typename T>
concept LikeFoo = requires (T t) {
{ t.a };
};
int main() {
std::list<Foo> ls = {{1},{2},{3},{4}};
std::list<std::reference_wrapper<Foo>> refs(ls.begin(), std::next(ls.begin(),2));
for(LikeFoo auto &foo : refs) {
std::cout << foo.a << std::endl;
}
return 0;
}
并希望它能奏效。clang
但是推导出foo
to的类型std::reference_wrapper<Foo>
,因此实际上下面的代码是正确的:
//this compiles with clang, but not with gcc
template<typename T>
concept LikeFoo = requires (T t) {
{ t.a };
};
int main() {
std::list<Foo> ls = {{1},{2},{3},{4}};
std::list<std::reference_wrapper<Foo>> refs(ls.begin(), std::next(ls.begin(),2));
for(LikeFoo auto &foo : refs) {
std::cout << foo.get().a << std::endl;
}
return 0;
}
但是,gcc
完全拒绝接受基于范围的 for 循环并抱怨deduced initializer does not satisfy placeholder constraints
,因为它试图检查LikeFoo<std::reference_wrapper<Foo>>
,这当然评估为 false,因此gcc
甚至无法捕获foo
概念限制。出现两个问题:
- 哪个编译器是正确的?应该
LikeFoo auto& foo : refs
有效吗? - 有没有一种方法可以自动捕获(可能是概念受限的)
foo : refs
,这样就可以避免get()
在for
循环体中写入?
您可以在编译器资源管理器中找到此示例。