【发布时间】:2014-11-20 09:11:00
【问题描述】:
我总是尽可能地尝试使用类似 STL 的算法,因为它们简洁且极具表现力。
我的一个库中有这段代码:
auto& findFlag(const std::string& mName)
{
for(auto& f : makeRangeCastRef<Flag>(getFlags()))
if(f.hasName(mName))
return f;
throw Exception::createFlagNotFound(mName, getNamesStr());
}
我想用现代 C++ 算法形式来写它,但我不知道如何处理早期的return 和可能的throw。
for(auto& value : container) if(predicate(value)) return value;
// ^~~~~~
// IMPORTANT: return from the caller function, not the algorithm itself
理想情况下,我想将真正的代码 sn-p 编写为:
auto& findFlag(const std::string& mName)
{
early_return_if(makeRangeCastRef<Flag>(getFlags()),
[&mName](const auto& f){ return f.hasName(mName); });
throw Exception::createFlagNotFound(mName, getNamesStr());
}
显然,像early_return_if 这样的东西是不存在的——据我所知,没有办法从被调用者的调用函数上调用return。 return early_return_if(...) 可以工作,但是如果不创建抛出异常的特定算法,我就无法抛出异常。
你有什么建议?应该保持代码原样还是有任何类似算法的方式我可以重写它?
编辑:
正如 cmets 中提到的,std::find_if 是一个很好的候选者,但是有一个可以避免的不必要的检查:
auto& findFlag(const std::string& mName)
{
auto container(makeRangeCastRef<Flag>(getFlags())); // Need to write this out...
// Need to keep track of the returned iterator...
auto it(findIf(container, [&mName](const auto& f){ return f.hasName(mName); }));
if(it != container.end()) return *it; // I don't like this either...
throw Exception::createFlagNotFound(mName, getNamesStr());
}
【问题讨论】:
-
对于
std::find_if<algorithm>来说听起来不错 -
auto it = std::find_if(begin(container), end(container), predicate); return it != end(container) ? *it : throw /*...*/; -
@T.C., @Cyber:我考虑过使用
std::find_if,但检查it != end(container)是不必要的,我想避免这种情况 -
@VittorioRomeo 您有
O(N)比较来查找元素,并且您关心(仅)在所有这些都失败的情况下,您会得到一个额外的吗? -
坚持循环,大声喊叫。您通过在不需要它们的地方强制使用算法来破坏您的代码,因为它们被认为是“现代的”(SGI STL 从 1994 年就已经存在,IIANM)。
标签: c++ algorithm lambda return c++14