范围::视图::通过引用或值枚举捕获?我们怎么能分辨



在下面的代码中,auto [i, e]auto&& [i, ee]都绑定了std::pair<int, T&>而不是std::pair<int, T>。有人能解释一下,如果没有实证检验,怎么会知道这一点吗?我想是range-v3实现。是否存在要使用auto&&而不是auto的情况?

auto container = std::array<int,3>{ 1,2,3 };
for (std::pair<int, int> p : ranges::views::enumerate(container))
p.second = 0; //Bad, of course 
print(container);
for (auto [i, e] : ranges::views::enumerate(container))
e = 0; //Okay???
print(container);
for (auto&& [i, ee] : ranges::views::enumerate(container))
ee = 42; //Okay???
print(container);
> [1,2,3]
> [0,0,0]
> [42,42,42]

https://godbolt.org/z/b7vrsxqK4

编辑:使用static_assert(std::is_reference_v<decltype(variable_name)>);


我很困惑,因为通常在ranged for循环中,当在迭代器上调用*运算符时,它会返回T&,所以必须添加ref限定符才能获得引用而不是副本。

for(auto& el : container)
--------------- 
auto& el = *it; // reference
for(auto el : container)
--------------- 
auto el = *it; // copy

然而,当*返回std::pair<int, T&>时,您不能再使用auto&,但现在auto将正常工作,因为它是被复制分配的对的引用,而不是对T&内部的引用。

将其与结构化绑定相结合,实际发生的事情非常令人困惑,因为下面的el实际上是一个参考:

for (auto [i, el] : views::enumerate(container))
el = 3; // OKAY!

要在将迭代器取消引用到给定范围时找到类型,可以使用

template<typename... Args> void whatis();
int main() 
{
auto container = std::array<int, 3>{ 1, 2, 3 };
auto it = ranges::views::enumerate(container).begin();
using traits = std::iterator_traits<decltype(it)>;
whatis<traits::reference>();
}

这将告诉你for(auto p : enumerate(container))中的推断类型将是ranges::common_pair<unsigned int,int &>

类似地,你可以发现ranges::views::enumerate(container)的类型是ranges::detail::index_view<unsigned int,int>,struct ranges::ref_view<class std::array<int,3>>>

从那里你可以开始研究源代码。CCD_ 20传递到CCD_ 21,CCD_

/// If it's a view already, pass it though.
template<typename T>
static constexpr auto from_range_(T&& t, std::true_type, detail::ignore_t,
detail::ignore_t)
{
return static_cast<T&&>(t);
}
/// If it is container-like, turn it into a view, being careful
/// to preserve the Sized-ness of the range.
template<typename T>
static constexpr auto from_range_(T&& t, std::false_type, std::true_type,
detail::ignore_t)
{
return ranges::views::ref(t);
}
/// Not a view and not an lvalue? If it's a borrowed_range, then
/// return a subrange holding the range's begin/end.
template<typename T>
static constexpr auto from_range_(T&& t, std::false_type, std::false_type,
std::true_type)
{
return make_subrange(static_cast<T&&>(t));
}
public:
template(typename T)(
/// pre
requires range<T&> AND viewable_range<T>)
constexpr auto operator()(T&& t) const
{
return all_fn::from_range_(static_cast<T&&>(t),
meta::bool_<view_<uncvref_t<T>>>{},
std::is_lvalue_reference<T>{},
meta::bool_<borrowed_range<T>>{});
}

然后,您可以查看ref_view,并看到它确实按照名称所示进行操作(参考底层容器(。

最新更新