0

我一直在更新我大约两年前编写的一个程序,我遇到了一个从字符串中删除所有标点符号和空格的调用。

调用工作正常,但我不确定这是最有效的方法。

代码行如下:

tempMessage.erase(remove_if(tempMessage.begin(), tempMessage.end(), (int(*)(int))ispunct), tempMessage.end());

我不记得我是从哪里想到这个的,也不记得它是如何组合在一起的,但我希望能够完全理解这个电话。

我知道 std::string.erase 摆脱了第一个参数,直到第二个参数。我还可以看到 remove_if 如何定义起点和终点,但是谁能告诉我 remove_if 调用中的第三个参数来自哪里?

我不记得为什么我的生活需要 (int(*)(int)) 。

当您查看代码时,任何人都可以改进它,或者提高它的效率吗?

谢谢

4

1 回答 1

1

首先,这通常不起作用;它似乎(并且它可能适用于某些编译器)。您不能将 a 传递char给一个参数版本ispunct而不引起未定义的行为。

至于强制转换的原因:标准定义了单参数ispunct函数双参数 ispunct函数模板。为了正确实例化模板函数erase,编译器需要知道ispunct. 要知道 的确切类型 ispunct,编译器需要能够对函数模板进行类型推导。为了进行类型推导,编译器需要知道预期的类型。依赖关系中有一个循环,显式转换(或看起来像显式转换)解决了该循环。

因为使用一个参数版本会ispunct导致未定义的行为,并且除非您提供附加参数( std::bind例如使用 ),否则使用两个参数版本将无法编译,所以在 C++ 中进行任何字符串处理的任何人都将拥有已经在他的工具箱来处理这个,并会写这样的东西:

tempMessage.erase(
    std::remove_if( tempMessage.begin(), tempMessage.end(), IsPunct() ),
    tempMessage.end() );

您如何实施IsPunct取决于您对本地化的需求。最简单的版本就是:

struct IsPunct
{
    bool operator()( char ch ) const
    {
        return ::ispunct( static_cast<unsigned char>( ch ) );
    }
};

使用ctypefacet 的版本locale稍微复杂一些(您可能希望它保留 的副本 locale以及对 facet 的引用,以确保引用的 facet 不会消失)。

于 2013-04-12T10:11:22.610 回答