【发布时间】:2021-10-07 03:17:42
【问题描述】:
我有一些类 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;
}
注意auto 捕获时附加的get(),因为我们推断出std::reference_wrapper<Foo> 类型,而在第二种情况下foo 已经隐式转换为Foo& 类型,因为我们显式捕获了此类型。
我实际上是在寻找一种方法来捕捉 auto 但隐含地抛弃了 std::reference_wrapper 以便不必一直在 for 正文中打扰 get() 方法,所以我尝试引入一个合适的概念并抓住了这一点,即我尝试过
//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 的类型推导出为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 甚至无法捕获 @ 987654342@ 概念受限。出现两个问题:
-
哪个编译器是正确的?
LikeFoo auto& foo : refs应该有效吗? - 有没有办法自动-catch(可能是概念受限的)
foo : refs,这样就可以避免在for-loop 主体中写入get()?
您可以在Compiler explorer 找到此示例。
【问题讨论】:
-
auto将始终推断出实际类型。为了获得Foo&,需要进行隐式转换。概念是对允许推导什么类型的约束。它无法应用转化。 -
是的,我也是这么想的,但是有没有办法在 range-for-loop 的初始化表达式中做到这一点?
-
您可以将
refs包裹在一个会自动为您提供get()每个元素的东西中。但是for (auto& foo : unwrap_reference_wrapper(refs))看起来更像是for (Foo& : refs)的更复杂的版本。不过它可以放在通用代码中。 -
是的,我正在编写大量通用代码,所以这将非常有用。但我不确定我会如何做到这一点,而不必编写一个全新的迭代器类等。
标签: c++ for-loop c++20 concept reference-wrapper