c++ - 在通用 C++ 代码中移动基于范围的循环?

标签 c++ for-loop c++17 generic-programming c++20

假设您有这个通用的伪代码:

template<typename Iterable>
void f(Iterable&& iterable)
{
   ...
}

我们想要处理对可迭代对象的右值和左值引用1,其想法是该函数处理逐个元素执行操作的容器。

我们想将容器的引用规范转发给元素是合理的。换句话说,如果 iterable 是一个右值引用,该函数将不得不从容器中移动元素。

使用 C++17,我会做

auto [begin, end] = [&] {
    if constexpr(std::is_lvalue_reference_v<Iterable>)
        return std::array{std::begin(iterable),
                          std::end(iterable)};
    else
        return std::array{
            std::make_move_iterator(std::begin(iterable)),
            std::make_move_iterator(std::end(iterable))};
}();
std::for_each(begin, end, [&](auto&& element)
{
    ...
});

显然,这不是维护2 的最佳代码,容易出错并且可能不太容易针对编译器进行优化。

我的问题是:对于 future 的 C++ 标准,是否有可能引入转发基于范围的循环的概念?如果这样就好了

for(auto&& el : std::move(iterable))
{
    ...
}

可以将 el 作为右值引用处理。这样,这将是可能的:

template<typename Iterable>
void f(Iterable&& iterable)
{
    for(auto&& el : std::forward<Iterable>(iterable))
    {
        /*
         *  el is forwarded as lvalue reference if Iterable is lvalue reference,
         *  as rvalue reference if Iterable is rvalue reference
         */
        external_fun(std::forward<decltype(el)>(el));
    }
}

我担心破坏代码的更改,但与此同时我无法考虑将右值引用作为基于范围的循环的参数传递的情况移动物体。

按照建议,我尝试写下我将如何更改标准的 6.5.4 部分。草稿可以阅读at this address .

您认为在不引入严重问题的情况下引入此功能是否可能?

1检查了 C++20 概念或 static_asserts
2如果没有 C++17,情况会更糟

最佳答案

这行不通。从根本上说,您可以迭代两种事物:拥有元素的事物和不拥有元素的事物。对于非拥有范围,范围的值(value)类别是无关紧要的。他们不拥有自己的元素,因此您无法安全地离开它们。基于范围的 for 循环必须适用于两种范围。

还有一些极端情况需要考虑(例如,代理迭代器)。基于范围的 for 循环基本上是语法糖,它只对被迭代的事物施加非常少的要求。好处是它可以迭代很多东西。代价是它没有太多聪明的余地。


如果您知道可迭代对象实际上拥有它的元素(因此移动是安全的),那么您所需要的只是一个根据其他事物的值类别转发某些事物的函数:

namespace detail {
    template<class T, class U>
    using forwarded_type = std::conditional_t<std::is_lvalue_reference<T>::value,
                                              std::remove_reference_t<U>&, 
                                              std::remove_reference_t<U>&&>;
}
template<class T, class U>
detail::forwarded_type<T,U> forward_like(U&& u) {
    return std::forward<detail::forwarded_type<T,U>>(std::forward<U>(u));
}

关于c++ - 在通用 C++ 代码中移动基于范围的循环?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46171843/

相关文章:

c++ - 为什么此线程池死锁或运行太多次?

c++ - Q_DECL_EXPORT 关键字含义

python - 在 for 循环 django 模板中添加列表限制

用于循环条件迭代和重置变量的 Javascript

c++ - 当 filesystem::path 被破坏时程序崩溃

c++ - 使用对嵌入的双端队列成员的引用初始化的树元素会为此导致 nullptr

c++ - 无法为处于不同线程中的父对象创建子对象

c++ - 使用操作当前对象的线程是否安全?

java - 如何使用计时器减慢 for 循环速度

binding - std::is_same 在使用 C++17 结构化绑定(bind)时给出奇怪的结果