我有一些类 Foo
和一个 std::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;
}
注意用 get()
捕获时额外的 auto
,因为我们推断出类型 std::reference_wrapper<Foo>
,而在第二种情况下 foo
已经隐式转换为类型 {{1}因为我们明确地抓住了这种类型。
我实际上是在寻找一种方法来捕捉 auto 但隐式地隐式抛弃了 Foo&
以便不必一直在 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));
for(LikeFoo auto &foo : refs) {
std::cout << foo.a << std::endl;
}
return 0;
}
然而将 clang
的类型推导出为 foo
,因此实际上下面的代码将是正确的:
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));
for(LikeFoo auto &foo : refs) {
std::cout << foo.get().a << std::endl;
}
return 0;
}
完全拒绝接受基于范围的 for 循环并抱怨 gcc
,因为它试图检查 deduced initializer does not satisfy placeholder constraints
,这当然评估为假,所以 {{ 1}} 甚至无法捕捉到 LikeFoo<std::reference_wrapper<Foo>>
概念限制。出现两个问题:
-
哪个编译器是正确的?
gcc
应该有效吗? - 有没有一种方法可以自动-catch(可能受概念限制)
foo
,这样就可以避免在{{1}中写入LikeFoo auto& foo : refs
}}-循环体?
您可以在 Compiler explorer 找到此示例。