基于范围的 for 循环表达式中的临时可选
Temporary optional in the range-based for loop expression
假设我们有一个函数 returns std::optional<A>
。那么在基于范围的 for 循环中使用结果的正确方法是什么?最简单的方法不行:
for (auto&& e : a().value()) {
// ^--- A&& is returned, so A is destructed
// before loop starts
如果我们用 T optional::value() &&
而不是 T&& optional::value() &&
,这个问题就不会存在,但是 STL 和 Boost 都以第二种方式定义它。
处理这种情况的正确方法是什么?我不喜欢我能想到的两种解决方案 (sandbox):
std::experimental::optional<A> a() {
// ...
}
void ok1() {
// ugly if type of A is huge
for (auto&& e : A(a().value())) {
// ...
}
}
void ok2() {
// extra variable is not used
// if for some reason we are sure that we have a value
// and we skip checks
auto&& b = a();
for (auto&& e : b.value()) {
// ...
}
}
// it may be that the best choice is to define
A aForced() {
return A(a().value());
}
这解决了您的问题:
template<class T>
std::decay_t<T> copy_of(T&& t){
return std::forward<T>(t);
}
template<class T, std::size_t N>
void copy_of(T(&)[N])=delete;
然后:
for(auto&& x:copy_of(a().value()))
copy_of
技术通常可以解决在 for(:)
循环中使用返回右值引用的函数。
另一种方法是编写 value_or_run(T&&, F&&f)
,它采用 lambda 也很有用。在 F
中你可以做任何你想做的事情,比如 throw,它 returns 是 T
而不是 T&&
.
同理,value_or
.
我个人的 optional
使用了 value_or
的 emplace 语法——如果您使用的是 .value_or( throw_if_empty{} )
,其中 throw_if_empty
有一个 operator T()
抛出可选的空错误。
假设我们有一个函数 returns std::optional<A>
。那么在基于范围的 for 循环中使用结果的正确方法是什么?最简单的方法不行:
for (auto&& e : a().value()) {
// ^--- A&& is returned, so A is destructed
// before loop starts
如果我们用 T optional::value() &&
而不是 T&& optional::value() &&
,这个问题就不会存在,但是 STL 和 Boost 都以第二种方式定义它。
处理这种情况的正确方法是什么?我不喜欢我能想到的两种解决方案 (sandbox):
std::experimental::optional<A> a() {
// ...
}
void ok1() {
// ugly if type of A is huge
for (auto&& e : A(a().value())) {
// ...
}
}
void ok2() {
// extra variable is not used
// if for some reason we are sure that we have a value
// and we skip checks
auto&& b = a();
for (auto&& e : b.value()) {
// ...
}
}
// it may be that the best choice is to define
A aForced() {
return A(a().value());
}
这解决了您的问题:
template<class T>
std::decay_t<T> copy_of(T&& t){
return std::forward<T>(t);
}
template<class T, std::size_t N>
void copy_of(T(&)[N])=delete;
然后:
for(auto&& x:copy_of(a().value()))
copy_of
技术通常可以解决在 for(:)
循环中使用返回右值引用的函数。
另一种方法是编写 value_or_run(T&&, F&&f)
,它采用 lambda 也很有用。在 F
中你可以做任何你想做的事情,比如 throw,它 returns 是 T
而不是 T&&
.
同理,value_or
.
我个人的 optional
使用了 value_or
的 emplace 语法——如果您使用的是 .value_or( throw_if_empty{} )
,其中 throw_if_empty
有一个 operator T()
抛出可选的空错误。