【问题标题】:Ranges V3 zip with auto and structured bindings具有自动和结构化绑定的 Ranges V3 zip
【发布时间】:2020-05-03 18:29:50
【问题描述】:

我希望能够使用 C++ 范围通过压缩容器来帮助简化代码逻辑,而不是显式索引到它们中。我可以让它与一个冗长的 lambda 参数一起工作,但我宁愿尝试使用更多 auto 使其更简单/可概括。

const int n = ...;
std::vector<float> a(n), b(n), c(n);

...initialize a and b...

// This works
ranges::for_each(
    ranges::views::zip(a, b, c),
    [](const std::tuple<float&, float&, float&>& v)
    {
        const auto& [a, b, c] = v;
        c = a + b; 
        std::cout << typeid(v).name(); // NSt3__15tupleIJRfS1_S1_EEE
    }
);

// This fails
ranges::for_each(
    ranges::views::zip(a, b, c),
    [](const auto& v)
    {
        const auto& [a, b, c] = v;
        // c = a + b; 
        std::cout << typeid(v).name(); // N6ranges12common_tupleIJRfS1_S1_EEE
    }
);

Ranges-v3 文档说明如下:

views::zip

给定 N 个范围,返回一个新范围,其中 Mth 元素是在所有 Mth 元素上调用 make_tuple 的结果N 个范围。

这让我觉得应该可以把ranges::common_tuple转换成std::tuple,看了看公众号发现:

std::tuple< Ts... > const & base() const noexcept

但是这也不能编译:

const auto& [a, b, c] = v.base();
// error: no member named 'base' in 'std::__1::tuple<float, float, float>'

但是当我打印typeid(v) 时,它不是std::tuple;它是ranges::common_tuple。我在这里尝试使用auto 类型扣除可能吗? (clang 编译器,如果这很重要)

【问题讨论】:

  • [](const &amp; v) { ... }v 的类型在哪里?尝试在那里添加auto 作为类型。
  • 糟糕,我打错了。应该是 [](const auto&amp; v){ ... } 导致 ranges::common_tuple

标签: c++ tuples c++17 auto structured-bindings


【解决方案1】:

简短的回答是:如果您实际上不需要const,请不要使用const。你想修改一些东西,为什么const?这工作正常:

ranges::for_each(
    ranges::views::zip(a, b, c),
    [](auto&& v)
    {
        auto&& [a, b, c] = v;
        c = a + b; 
    }
);

较短的也是如此:

for (auto&& [a, b, c] : ranges::views::zip(a, b, c)) {
    c = a + b;
}

你休息的原因有点微妙。基本上,ranges::for_each 受限于indirectly_unary_invocable,这需要所有:

        invocable<F &, iter_value_t<I> &> &&
        invocable<F &, iter_reference_t<I>> &&
        invocable<F &, iter_common_reference_t<I>> &&

因此,您的 lambda 会使用所有这三种类型进行实例化。其中一种类型 (iter_value_t&lt;I&gt;&amp;) 是 tuple&lt;float, float, float&gt;&amp;。因此,当您使用const auto&amp; 进行结构化绑定时,每个绑定的类型都是const float。这就是它不可分配的原因——但这仅适用于特定的实例化(无论如何,它不是在运行时被调用的实例化)。

【讨论】:

  • 完美!我一直在使用 const,因为 TBB 在 analogous example 中使用它并且在尝试 auto&amp; 时遇到了问题
猜你喜欢
  • 2019-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-11-24
  • 1970-01-01
  • 1970-01-01
  • 2011-12-12
相关资源
最近更新 更多