std :: transform到任意容器

时间:2014-11-04 08:43:16

标签: c++ c++11 std

我想编写接收container1值为[a1, .. , an]的通用函数,并返回值为container2的另一个[convert(a1), .. , convert(an)]。 如果container2std::vector,则问题很简单,std::transform完全符合我的要求。以下函数可以处理任意container2container1

template<class ToType, class FromType>
ToType convert(const FromType& from)
{
    std::vector<typename ToType::value_type> tmp;
    std::transform(from.begin(), from.end(),
                   std::back_inserter(tmp),
                   [](const typename FromType::value_type& f) {
        return convert<typename ToType::value_type>(f);
    });
    return ToType(tmp.begin(), tmp.end());
}

但它确实添加了副本。有谁知道怎么做得更好?

2 个答案:

答案 0 :(得分:3)

结帐this answerIs it possible to write a C++ template to check for a function's existence?。您可以使用SFINAE来检测目标容器的功能是否存在(例如push_backinsert),或者是否存在容器的插入器(例如inserter或{{1} }),并相应地表现。

另一种方法是创建一个伪迭代器:

back_inserter

然后:

template <class T, class U>
struct ConvertIterator {
    typedef T dest_type;
    typedef U it_type;

    ConvertIterator(U&& val) : iterator(std::forward<U>(val)) {

    }

    bool operator == (const ConvertIterator &other) const {
        return iterator == other.iterator;
    }

    bool operator != (const ConvertIterator &other) const {
        return iterator != other.iterator;
    }

    dest_type operator * () const {
        return convert<dest_type>(*iterator);
    }

    ConvertIterator<T, U> & operator ++() {
        ++iterator;
        return *this;
    }

    it_type iterator;
};

答案 1 :(得分:0)

这是一个基于函数的转换迭代器。它具有前向迭代器的所有正确的typedef。如果我们选择的话,我们可以升级它以支持传入的Base迭代器类型的所有标记属性:

template<
  class Base,
  class F,
  class R=typename std::result_of<F(decltype(*std::declval<Base const&>()))>::type
>
struct convert_iterator:
  std::iterator<std::forward_iterator_tag,typename std::decay<R>::type>
{
  Base it;
  F f;

  template<class It, class Func>
  convert_iterator(It&&base, Func&&func):it(std::forward<It>(base)),
  // defaulted stuff:
  convert_iterator()=default;
  convert_iterator(convert_iterator const&)=default;
  convert_iterator(convert_iterator &&)=default;
  convert_iterator& operator=(convert_iterator const&)=default;
  convert_iterator& operator=(convert_iterator &&)=default;

  bool operator==(convert_iterator const&other) const {
    return it == other.it;
  }
  bool operator!=(convert_iterator const&other) const { return !(*this==other); }

  // a bit overkill, but rvalue and lvalue overrides for these:
  R operator*() const& {
    return f(*it);
  }
  R operator*() & {
    return f(*it);
  }
  R operator*() const&& {
    return std::move(f)(*std::move(it));
  }
  R operator*() && {
    return std::move(f)(*std::move(it));
  }
  // normal pre-increment:
  convert_iterator& operator++()& {
    ++it;
    return *this;
  }
  // pre-increment when we are guaranteed not to be used again can be done differently:
  convert_iterator operator++()&& {
    return {std::next(std::move(it)), std::forward<F>(f)};
  }
  // block rvalue post-increment like a boss:
  convert_iterator operator++(int)& {
    return {it++, f};
  }
};

创建它们的辅助函数:

template< class Base, class F >
convert_iterator<typename std::decay<Base>::type,typename std::decay<F>::type>
make_convert_iterator(Base&& b, F&& f) { return {std::forward<Base>(b), std::forward<F>(f)}; }

接下来,我创建一个处理转换的类。专业化允许我们对容器和标量进行不同的调度:

// for scalars:
template<class ToType,class=void>
struct converter {
  template<class FromType>
  ToType operator()(FromType&& from)const{ return std::forward<FromType>(from); }
};

// attempt at SFINAE test for container:
template<class ToContainer>
struct converter<ToContainer, (void)(
  typename std::iterator_traits<
    typename std::decay<decltype(std::begin(std::declval<ToContainer&>())>::type
  >::value_type
)>
{
  using std::begin; using std::end;

  using R=std::iterator_traits<typename std::decay<decltype(begin(std::declval<ToContainer&>()))>::type>::value_type;

  template<class FromType, class T=decltype(*begin(std::declval<FromType>())>
  ToContainer operator()(FromType&& from) const {
    auto sub_convert = [](T&& t)->R{
      return converter<R>{}(std::forward<T>(t));
    };
    return {
      make_convert_iterator(begin(std::forward<From>(from)), sub_convert),
      make_convert_iterator(end(std::forward<From>(from)), sub_convert)
    };
  };
};

动作转换功能现在是一行代码:

template<class ToType>
ToType convert(FromType&& from)
{
  return converter<ToType>{}(std::forward<FromType>(from));
}