Combinando algoritmos padrão C ++ fazendo loop somente uma vez

Atualmente, tenho este código em funcionamento:

string word="test,";
string::iterator it = word.begin();
for (; it != word.end(); it++)
{
    if (!isalpha(*it)) {
        break;
    }
    else {
       *it = toupper(*it);
    }
}
word.erase(it, word.end());
// word should now be: TEST

Eu gostaria de torná-lo mais compacto e legível por:

Compor algoritmos C ++ padrão existentes (*)Execute o loop apenas uma vez

(*) Estou assumindo que combinar algoritmos existentes torna meu código mais legível ...

Uma solução alternativa

Além de definir um costumetransform_until algoritmo, como sugerido por jrok, pode ser possível definir um adaptador de iterador customizado que iria iterar usando o iterador subjacente, mas redefinir o operador * () modificando a referência subjacente antes de retorná-lo. Algo parecido:

template <typename Iterator, typename UnaryFunction = typename Iterator::value_type (*)(typename Iterator::value_type)>
class sidefx_iterator: public std::iterator<
                         typename std::forward_iterator_tag,
                         typename std::iterator_traits<Iterator>::value_type,
                         typename std::iterator_traits<Iterator>::difference_type,
                         typename std::iterator_traits<Iterator>::pointer,
                         typename std::iterator_traits<Iterator>::reference >
{
  public:
    explicit sidefx_iterator(Iterator x, UnaryFunction fx) : current_(x), fx_(fx) {}

    typename Iterator::reference operator*() const { *current_ = fx_(*current_); return *current_; }
    typename Iterator::pointer operator->() const { return current_.operator->(); }
    Iterator& operator++() { return ++current_; }
    Iterator& operator++(int) { return current_++; }
    bool operator==(const sidefx_iterator<Iterator>& other) const { return current_ == other.current_; }
    bool operator==(const Iterator& other) const { return current_ == other; }
    bool operator!=(const sidefx_iterator<Iterator>& other) const { return current_ != other.current_; }
    bool operator!=(const Iterator& other) const { return current_ != other; }
    operator Iterator() const { return current_; }

  private:
    Iterator current_;
    UnaryFunction fx_;
};

Claro que isso ainda é muito cru, mas deveria dar a idéia. Com o adaptador acima, eu poderia escrever o seguinte:

word.erase(std::find_if(it, it_end, std::not1(std::ref(::isalpha))), word.end());

com o seguinte definido com antecedência (o que poderia ser simplificado por algum modelo mágico):

using TransformIterator = sidefx_iterator<typename std::string::iterator>;
TransformIterator it(word.begin(), reinterpret_cast<typename std::string::value_type(*)(typename std::string::value_type)>(static_cast<int(*)(int)>(std::toupper)));
TransformIterator it_end(word.end(), nullptr);

Se o padrão incluir um desses adaptadores, eu o usaria, porque isso significaria que ele era perfeito, mas como esse não é o caso, provavelmente vou manter meu loop como está.

Tal adaptador permitiria reutilizar algoritmos existentes e misturá-los de diferentes maneiras não possíveis hoje, mas também pode ter desvantagens, o que provavelmente estou negligenciando no momento ...

questionAnswers(2)

yourAnswerToTheQuestion