2013-04-12 5 views
0

Я обновляю программу, которую написал почти два года назад, и я столкнулся с вызовом, чтобы удалить все знаки препинания и пробелы из строки.Удаление вопроса о пунктуации

Звонок работает нормально, но я не уверен, что это самый эффективный способ сделать это.

Строка кода ниже:

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

У меня нет никаких воспоминаний о том, где я придумал это или как он был поставлен вместе, но я хочу, чтобы иметь возможность полностью понять этот вызов.

Получаю, что std :: string.erase избавляется от первого аргумента до второго аргумента. Я также вижу, как remove_if определяет начальную и конечную точки, но может ли кто-нибудь сказать мне, откуда идет третий аргумент в вызове remove_if?

Я не могу вспомнить, почему (int (*) (int)) требуется для жизни меня.

Пока вы смотрите на код, может ли кто-нибудь улучшить это или сделать его более эффективным?

Thanks

ответ

1

Во-первых, это не работает вообще; это просто кажется (и это может работать с некоторыми компиляторами). Вы не можете передать 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)); 
    } 
}; 

версия используя ctype грань locale несколько сложнее (и вы, вероятно, хотите, чтобы сохранить копию locale, а также ссылку на фаской, просто чтобы , что ссылка на фасет не исчезает).

+0

Кажется, что я искал быстрое решение в то время, и это сработало. Не могли бы вы объяснить структуру, которую вы определили в своем ответе, немного больше? Похоже, что он возвращает true, если char является символом punct, но я не понимаю два полуколона перед развязным вызовом. Я также не очень хорошо знаком с реализацией bool operator() const. Не могли бы вы также расширить это? Извините за хлопот. – Matthew

+0

Нет проблем. '::' - оператор разрешения области. Он просто гарантирует, что мы получаем 'ispunct' из' ', а не другой. (Это не обязательно здесь.) 'Bool operator() (...)' - оператор вызова функции: это означает, что компилятор может «вызывать» объект, как если бы он был функцией. Такие объекты называются функциональными объектами или функторами и широко используются в C++. –

+0

Просто для моей собственной ясности. как передается 'char' в' int ispunct (int ch) 'undefined поведение, но передача' unsigned char' is * not *? Является ли первое не охваченным результатом интегральных повышений в стандарте (4.5/4.7), а если нет, то как последний? – WhozCraig

Смежные вопросы