通过循环只有一次结合C ++标准算法 [英] Combining c++ standard algorithms by looping only once

查看:200
本文介绍了通过循环只有一次结合C ++标准算法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

目前,我有这个code和运行:

I currently have this code up and running:

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

我想,使其更加紧凑和可读的:

I would like to make it more compact and readable it by:

  1. 组合现有的标准C ++算法(*)
  2. 执行循环一次

(*)我假设,结合已有的算法使我的code更具可读性...

(*) I'm assuming that combining existing algorithms makes my code more readable...

在此先感谢,

JM

除了定义自定义的 transform_until 算法,所建议的jrok,有可能定义一个自定义的迭代器适配器,将循环使用底层迭代器,但重新定义运营商*()通过返回之前修改基础参考。 类似的东西:

In addition to defining a custom transform_until algorithm, as suggested by jrok, it might be possible to define a custom iterator adaptor that would iterate using the underlying iterator but redefine operator*() by modifying the underlying reference before returning it. Something like that:

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_;
};

当然,这还是很原始,但应该给这个想法。 有了上述的适配器,然后,我可以写:

Of course this is still very raw, but should give the idea. With the above adaptor, I could then write the following:

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

与以下事先定义(这可以通过一些模板魔术被简化):

with the following defined in advance (which could be simplified by some template-magic):

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);

如果该标准将包括这样的适配器我会用它,因为这将意味着它是完美的,但由于这是不是这样我可能会继续我的循环,因为它是。 这种适配器将允许重新使用现有的算法和不可能今天将它们混合以不同的方式,但它可能有不足之处为好,这是我此刻的我可能俯瞰...

If the standard would include such an adaptor I would use it, because it would mean that it was flawless, but since this is not the case I'll probably keep my loop as it is. Such an adaptor would allow to reuse existing algorithms and mixing them in different ways not possible today, but it might have downsides as well, which I'm likely overlooking at the moment...

推荐答案

我不认为有一个干净的方式用一个标准的算法做到这一点。没有,我知道需要predicate(你需要一个决定何时突破前期),并允许修改源序列的元素。

I don't think there's a clean way to do this with a single standard algorithm. None that I know of takes a predicate (you need one to decide when to break early) and allows to modify the elements of the source sequence.

您可以编写自己的遗传算法,如果你真的想这样做标准的方式。让我们把它叫做,嗯, transform_until

You can write your own generic algorithm if you really want to do it "standard" way. Let's call it, hmm, transform_until:

#include <cctype>
#include <string>
#include <iostream>

template<typename InputIt, typename OutputIt,
         typename UnaryPredicate, typename UnaryOperation>
OutputIt transform_until(InputIt first, InputIt last, OutputIt out,
                         UnaryPredicate p, UnaryOperation op)
{
    while (first != last && !p(*first)) {
        *out = op(*first);
        ++first;
        ++out;
    }
    return first;
}

int main()
{
    std::string word = "test,";
    auto it =
    transform_until(word.begin(), word.end(), word.begin(),
                    [](char c) { return !::isalpha(static_cast<unsigned char>(c)); },
                    [](char c) { return ::toupper(static_cast<unsigned char>(c)); });
    word.erase(it, word.end());
    std::cout << word << '.';
}

这是值得商榷的,这是否是任何比你:)有时for循环平原是最好,只有更好。

It's debatable whether this is any better than what you have :) Sometimes a plain for loop is best.

这篇关于通过循环只有一次结合C ++标准算法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆