【发布时间】:2017-09-12 08:45:57
【问题描述】:
想象一下你有这个通用的伪代码:
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,容易出错,而且可能不太容易为编译器优化。
我的问题是:对于未来的 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));
}
}
我担心破坏代码的更改,但同时我无法考虑将右值引用作为基于范围的循环的 argument 传递的情况移动物体。
按照建议,我尝试写下我将如何更改标准的 6.5.4 部分。草稿可以阅读at this address。
您认为可以在不引入严重问题的情况下引入此功能吗?
1用 C++20 概念或 static_asserts 检查
2而且没有 C++17 就更糟了
【问题讨论】:
-
这个有什么用例?
-
您不应该在循环中使用
std::forward而不是std::move吗? -
@EyalK。在编写多线程 for 循环包装器时,我想到了这个问题,但我认为它可以适用于许多情况。
-
您能否为这种新的循环添加一个实际提议的规范?否则很难评估这个想法。
-
改写@KerrekSB 的问题,this 是基于范围的
for当前扩展到的内容。您想要更改其中的哪一部分,以及如何更改?
标签: c++ for-loop c++17 generic-programming c++20