Obecnie mam ten kod i działa:Łącząc C++ standardowych algorytmów poprzez zapętlenie tylko raz
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
chciałbym uczynić go bardziej zwarty i czytelny go:
- Komponowanie istniejącej standardowej C++ algorytmów (*)
- Wykonać pętli tylko raz
(*) mi zakładając, że c ombining istniejących algorytmów sprawia, że mój kod bardziej czytelny ...
Alternatywnym rozwiązaniem
Oprócz definiowania algorytmu zwyczaj transform_until
, jak sugeruje jrok, może to być możliwe określenie adaptera zwyczaj iterator że iterację korzystania podstawowym iteratorem, ale przedefiniuj operatora *(), modyfikując bazowe odniesienie przed zwróceniem go. Coś takiego:
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_;
};
Oczywiście jest to nadal bardzo surowy, ale powinny dać pomysł. Z powyższej karty, mógłbym wtedy napisać następujące:
word.erase(std::find_if(it, it_end, std::not1(std::ref(::isalpha))), word.end());
z następujących zdefiniowane wcześniej (co może być uproszczona przez jakiś szablon magii):
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);
Jeśli średnia obejmowałyby takiego adaptera użyłbym, ponieważ oznaczałoby to, że był bezbłędny, ale ponieważ tak nie jest, prawdopodobnie zachowam pętlę taką, jaka jest.
Taki adapter pozwoli na ponowne wykorzystanie istniejących algorytmów i mieszanie ich w inny sposób nie jest możliwe dzisiaj, ale może mieć także wady, które ja prawdopodobnie widokiem na chwilę ...
W moim bieżącym kodzie jest jedna pętla. Chodzi mi o to, że po przepisaniu wciąż będzie jedna pętla. –
Przedwczesny exodus oparty na '! Isalpha (* it)' jest jedyną rzeczą, którą widzę potencjalnie powstrzymując cię od osiągnięcia tego, czego myślę, że szukasz, i szczerze mówiąc, wszystkiego, co może zrobić to dla twojego (i nie mogę zobaczysz wszystko, co by to zrobiło) byłoby tak zawiłe, że masz czynnik jasności, który wyszedłby przez okno. Pewnie bym się trzymał tego, co masz. – WhozCraig
Dziękuję wszystkim za inspirujące odpowiedzi. Na razie trzymam się mojego obecnego kodu. Wierzę, że 'boost :: transform_iterator' jest najbliższą rzeczą, której szukałem. Ten przypadek użycia zostanie objęty adapterem iteratora "efektów ubocznych", czymś takim, który będzie używany w następujący sposób: 'word.erase (std :: find_if (sidefx_iterator (word.begin(), :: toupper), word.end (), std :: not1 (:: isalpha)), word.end()); ' –