如何从lambda函数中返回?
考虑下面的玩具代码,以确定范围是否包含一个元素:如何从lambda函数中返回?
template<typename Iter, typename T>
bool contains1(Iter begin, Iter end, const T& x)
{
for (; begin != end; ++begin)
{
if (*begin == x) return true;
}
return false;
}
(是的,我知道,有标准库已经完全正常的算法,这不是问题的关键。)
如何我会写for_each
和lambda?以下不起作用...
template<typename Iter, typename T>
bool contains2(Iter begin, Iter end, const T& x)
{
std::for_each(begin, end, [&x](const T& y) {
if (x == y) return true;
});
return false;
}
...因为那只会从lambda返回,而不是从函数返回。
我必须抛出异常才能摆脱lambda?同样,对于这个不涉及lambda的特定问题,可能有十多个更好的解决方案,但这并不是我所要求的。
我该怎么写
for_each
和lambda?
您不能(不考虑例外情况)。你的函数不是和for-each循环同构的(=一种映射),它就像那样简单。
相反,您的功能是通过缩小来描述的,所以如果您想使用高阶函数来替换它,请使用缩减而不是地图。
如果 C++ 有合适,通用reduce
那么你的算法将如下所示:
template<typename Iter, typename T>
bool contains2(Iter begin, Iter end, const T& x)
{
return stdx::reduce(begin, end, [&x](const T& y, bool accumulator) {
return accumulator or x == y;
});
}
当然,这只是退出早在压下正确专门用于布尔结果值,以便短路。
唉,C++没有提供这样的功能,据我所知。有accumulate
但不会短路(它不能 - C++不知道操作里面的lambda是短路的,它不是递归实现的)。
如果您希望通用的reduce实现短路,则需要使用惰性类型 – ysdx
@ysdx你可以专门研究函数的特征('is_short_circuited'),不是很优雅,而是一般用途。 –
在这种情况下,lambda就像从给定函数contains2()
调用的任何其他函数一样。从其他函数返回并不意味着你从给定函数返回。因此,这是不可能这就是设计应该如何去。
对于像给定例子那样的模式,抛出异常是不必要的开销。我会在lambda表中设置一个bool
变量,而不是return
(也可以设置begin = end;
)。这个bool
可以检查从给定函数contains2()
返回。
std::for_each
如果您想尽早结束循环,则不是您应该使用的算法。看来你想要std::find_if
或类似的东西。您应该使用最适合您的任务的算法,而不仅仅是您熟悉的算法。
如果你真的,真的,真的必须从算法早期的 “回归”,你能够 -
警告:接踵而来的是一个真正的,实在坏主意和你几乎不应该这样做。确实,看代码可能会让你的脸变得模糊。 你已被警告!
抛出一个异常:
bool contains2(Iter begin, Iter end, const T& x)
{
try {
std::for_each(begin, end, [&x](const T& y) {
if (x == y)
throw std::runtime_error("something");
});
}
catch(std::runtime_error &e) {
return true;
}
return false;
}
你基本上只是在没有问号的情况下重新解释这个问题,他* *他知道有更合适的'std'算法,并且他提到了抛出异常的可能性。 – jalf
-1什么是jalf表示 – IronMensan
Lambda表达式是错误的抽象级别,因为他们的行为在很大程度上类似的功能 - 至少当它涉及到控制流,这是这里最重要的。你不想把某些东西当作一个函数(或程序编程的程序)“封装”,它只能在C++中直接返回或抛出异常。任何颠覆这种行为的企图都应该被认为是病态的 - 或者至少不应该伪装成一种程序。
对于执行流程的细粒度控制,类似于协程的东西可能是更适合的抽象级别和/或基元。尽管如此,恐怕最终的结果看起来不会像使用std::for_each
。
使用自定义算法:
template<class I, class F>
bool aborting_foreach(I first, I last, F f) {
while(;first!=last;++first) {
if(!f(*first))
return false;
}
return true;
}
好吧,其实这是性病:: all_of但你的想法。 (请参阅“缩小答案”)。如果你的函数需要返回某些类型的,你可能想要使用一些变量类型:
// Optional A value
template<class A>
class maybe {
// ...
};
或
// Stores either a A result of a B "non local return"
template<class A, class B>
class either {
…
};
请参见相应的哈斯克尔类型。你可以使用C++ 01“unrestricted union”来实现这一点。
干净的方式做非本地退出,使用continuations,但你没有他们在C + +。
正如你和其他人指出的for_each
不是在这里使用的正确算法。没有办法摆脱for_each
循环 - 除了例外(双关意图) - 你必须完全运行它。
template<typename Iter, typename T>
bool contains2(Iter begin, Iter end, const T& x)
{
bool tContains = false;
std::for_each(begin, end, [&](const T& y) mutable {
tContains = tContains || x == y;
});
return tContains;
}
使用std::any_of。
template<typename Iter, typename T>
bool contains2(Iter begin, Iter end, const T& x)
{
const bool contains = std::any_of(begin, end, [&x](const T& y)
{
return x == y;
});
return contains;
}
你不能从lambda这样返回。对编译器来说,Lambda是另一个函数,可以在其他地方传递。将lambda传递给另一个方法会非常愚蠢,在这种方法中,调用会跳到2个级别,不是吗? – nothrow
如果你不想处理所有的元素,你真的不应该使用for_each。 –
你不能这样做。您可以通过许多其他方式实现相同的效果。你有没有一个没有人为的例子,它实际上是值得的? – Mankarse