gpt4 book ai didi

c++ - std::list> 的基于概念限制范围的 for 循环

转载 作者:行者123 更新时间:2023-12-04 07:19:12 25 4
gpt4 key购买 nike

我有课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() catch 时 auto ,正如我们推断类型 std::reference_wrapper<Foo> ,而在第二种情况下 foo已经隐式转换为类型 Foo&因为我们明确地捕获了这种类型。
我实际上是在寻找一种方法来捕捉 auto 但隐含地抛弃了 std::reference_wrapper隐含地为了不必打扰 get()方法一直在 for body ,所以我尝试引入一个合适的概念并捕获这个,即我试过
//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>> ,当然评估为假,所以 gcc一个人都抓不到 foo概念限制。出现两个问题:
  • 哪个编译器是正确的? LikeFoo auto& foo : refs有效吗?
  • 有没有办法自动捕获(可能受概念限制)foo : refs这样就可以避免必须写get()for -循环体?

  • 您可以在 Compiler explorer 上找到此示例。 .

    最佳答案

    Which of the compilers is correct? Should LikeFoo auto& foo : refs be valid?


    refs是一个范围 reference_wrapper<Foo>& , 所以 foo推导出对 reference_wrapper<Foo> 的引用- 没有名为 a 的成员.约束变量声明不会改变推导的工作方式,它只是有效地表现得像一个额外的 static_assert .

    Is there a way to auto-catch (possibly concept-restricted) foo : refs such that one can avoid having to write get() in the for-loop body?


    只需写信 refs ?不。但是你可以写一个范围适配器来转换你的范围 reference_wrapper<T>范围为 T& .标准库中已经有这样的东西了, transform :
    for (auto &foo : refs | std::views::transform([](auto r) -> decltype(auto) { return r.get(); })) {
    这是一口,所以我们可以让它自己命名适配器:
    inline constexpr auto unwrap_ref = std::views::transform(
    []<typename T>(std::reference_wrapper<T> ref) -> T& { return ref; });
    然后你可以写:
    for (auto &foo : refs | unwrap_ref) { ... }
    for (auto &foo : unwrap_ref(refs)) { ... }
    无论哪种方式, foo这里推断为 Foo .
    再多做一点工作,您就可以编写一个范围适配器来解包 reference_wrapper<T>但保留任何其他引用类型。

    关于c++ - std::list<std::reference_wrapper<T>> 的基于概念限制范围的 for 循环,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/68610246/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com