是否存在range :: view :: transform的可修改视图版本?

时间:2019-04-21 22:38:03

标签: c++ range-v3 range-view

考虑以下程序:

#include <iostream>
#include <algorithm>
#include <numeric>
#include <array>
#include <range/v3/view/transform.hpp>

int main() {
    using container = std::array<std::tuple<int,float,double>, 4>;
    container tuples {{
        {1, 4.f, 8.},
        {2, 5.f, 9.},
        {3, 6.f, 10.},
        {4, 7.f, 11.}
    }};

    auto int_view =
        tuples | ranges::view::transform( [](auto& t){return std::get<int>(t);} );

    // int_view[1] = 3; // (*)

    auto x = std::accumulate(int_view.begin(), int_view.end(), 0);
    std::cout << "x = " << x << std::endl;
}

这将编译并打印10;但是-如果我取消对(*)行的注释-它不会编译,因为GCC抱怨等式的左侧不是左值。我对此感到失望-我有点希望转换会产生int&,可以分配给......

我可以做些修改吗?还是Ranges库中的某些其他机制可以让我获得等同于可修改视图的功能?

1 个答案:

答案 0 :(得分:3)

如果考虑一下,代码的问题很简单:

变换函数实际上是投影函数,您不会产生允许修改源代码所需的引用,因为the standard return type deduction rule for lambdas使用rules for plain auto,而这些函数从不推导引用。

  1. One fix is changing to the deduction rules for decltype(auto),它保留引用,因此最好避免使用,除非您知道它们是正确的。

    auto int_view = tuples | ranges::view::transform(
        [](auto& t)->decltype(auto){return std::get<int>(t);});
    
  2. 或者您可以使用auto&或更具体的内容来明确要求引用。

    auto int_view = tuples | ranges::view::transform(
        [](auto& t)->auto&{return std::get<int>(t);});
    
  3. 最后,没有人阻止您返回诸如std::reference_wrapper之类的代理。虽然这是不必要的复杂性。

    auto int_view = tuples | ranges::view::transform(
        [](auto& t){return std::ref(std::get<int>(t));});