如何优化此find_if代码?

时间:2010-11-11 01:11:49

标签: c++

我有函数检查一个字符串是否只包含字母数字和下划线字符......

inline bool IsValidChar(char x) 
{ 
    return (isalnum(x) || (x == '_')); 
} 

我的find_if代码是:

if(find_if(str.begin(), str.end(), IsValidChar) != str.end()) 
{ 
    ... 
} 

我只想删除IsValidChar函数并直接将其内容放在find_if代码行中。

5 个答案:

答案 0 :(得分:8)

你基本上在寻找C++0x lambda expressions

if (find_if(str.begin(), str.end(),
    [](char x) { return (isalnum(x) || x == '_'); })
    != str.end()) {
    // Do something.
} 

答案 1 :(得分:1)

FrédéricHamidi为您提供了一个很好的例子,说明如何使用lambda表达式来实现您的字面意思。但是,问题的标题是“如何优化此find_if代码”(强调我的)。匿名函数和命名函数之间的性能差异可以忽略不计(希望为零!)。理想情况下,任一版本都可以完全内联(假设find_if是内联的),甚至lambda表达式和命名函数之间的细微差别也无关紧要。

如果(这是一个很大的问题)你已经分析了你的代码并发现这个表达式是性能瓶颈的根源,那么你会想要探索另一种算法来获得相同的结果。由于这是一个如此简单的测试(并且不太可能进一步简化),因此您需要了解如何在更高级别上更频繁地进行此测试。

答案 2 :(得分:1)

标准C ++

标准C ++方法从<functional>标头开始,但它不提供所需的一切。我们必须or两个谓词条件,虽然SGI的STL(以及因此GCC)和其他人提供它作为一个名为“compose2”的扩展,如果你的编译器缺少这样的函数,那么你可以复制实现(并阅读它在)http://accu.org/index.php/journals/443

使用compose2,您可以写:

#include <functional>
#include <ext/functional> // where GNU g++ hides its compose2

find_if(str.begin(), str.end(),
        __gnu_cxx::compose2(
            std::logical_or<bool>(),
            std::ptr_fun(isalnum),
            std::bind1st(std::equal_to<int>(), '_')));

这一切都非常符合逻辑,但是冗长而且阅读速度慢。

使用BOOST库

领先的非标准C ++“工具箱”库 - BOOST - 提供了多种替代方案。我将说明Lambda - 请参阅http://www.boost.org/doc/libs/1_44_0/doc/html/lambda.html

#include <boost/lambda/lambda.hpp>
#include <boost/lambda/bind.hpp>
...
    find_if(str.begin(), str.end(),
            bind(isalnum, boost::lambda::_1) || boost::lambda::_1 == '_');

如果您愿意:

...
using namespace boost::lambda;
...
            bind(isalnum, _1) || _1 == '_');

<强>的C ++ 0x

FWIW,下一个C ++标准(现在很快就会发布,并且已经在几个流行编译器的最新版本中部分实现)将为lambda提供更好的内置支持:

...
            [](char x) { return isalnum(x) || x == '_'; });

<强>讨论

考虑到这一切有多大麻烦,你一定想知道是否最好坚持你的开始。大概。尽管如此,如果你有很多想要使用它们的地方并且每个地方的谓词都不同,这些lambda事情确实会有所帮助。

答案 3 :(得分:0)

你可以这样做:

if(str.find_first_not_of("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_")!=std::string::npos)
{
    ...
}

在这种情况下,我真的不认为这更清楚。 (如果你有更小或更多的任意字符集,这种方法是最干净的。)但它摆脱了额外的功能。而且,如果它很重要,它与之前的C ++标准兼容。

答案 4 :(得分:0)

我看到的主要问题是它找到了第一个有效字符。

如果要排除字符串中的无效数据,似乎需要反转谓词的意义。

inline bool IsNotValidChar(char x) 
{ 
    return (!isalnum(x) && (x != '_')); 
}

if(find_if(str.begin(), str.end(), IsNotValidChar) != str.end()) 
{ 
    ... 
} 

正如其他人所说,lambda表示法使这更简洁,但不一定更清晰,绝对不会更快。