C++以迭代器作为参数的成员函数

C++ member function with iterator as parameter

本文关键字:成员 函数 参数 迭代器 C++      更新时间:2023-10-16

我想写一个类test,它能够存储一个函数,该函数能够遍历由经典[first,last)迭代器对标识的元素集合,即:

template <typename T>
struct sum
{
  template <typename I>
  T operator()(I first, I last) const
  {
    T res = 0;
    while (first != last)
    {
      res += *first;
      ++first;
    }
    return res;
  }
};
//...
int main()
{
  test<double> t;
  t.set(sum<double>);
  double a[] {1.,2.,3.};
  std::cout << "Test (array) => " << t.call(a, a+3) << std::endl;
  std::vector<double> v {1.,2.,3.};
  std::cout << "Test (vector) => " << t.call(v.begin(), v.end()) << std::endl;
  std::list<double> l {1.,2.,3.};
  std::cout << "Test (list) => " << t.call(l.begin(), l.end()) << std::endl;
}

我想使用 std::function ,但我未能做到这一点,因为我无法声明模板化的迭代器对。一个可能的解决方法如下,但是它仅适用于普通数组(例如,double[]double*,如上面的变量 a ),而不适用于其他容器(例如,如上述变量 vl):

template <typename T>
class test
{
public:
  template <typename F>
  void set(F f)
  {
    f_ = f;
  }
  template <typename I>
  T call(I first, I last) const
  {
    return f_(first, last);
  }
private:
  std::function<T(T*,T*)> f_;
};

关于如何获得正确行为的任何想法?

注意:我正在使用GCC 4.9.2 --std=c ++ 11进行编译

谢谢。

你想要的是能够构造一个:

std::function<T(FwdIter<T>, FwdIter<T>)>

其中FwdIter<T>是一些类型擦除的类,它满足了 ForwardIterator 概念并被取消引用到T 。为此,请查看Boost.TypeErasure库,我们可以在其中执行以下操作:

#include <boost/type_erasure/any.hpp>
#include <boost/type_erasure/operators.hpp>
#include <boost/mpl/vector.hpp>
using namespace boost::type_erasure;
template <typename T>
using FwdIter = any<
    boost::mpl::vector<
        copy_constructible<>,
        incrementable<>,
        dereferenceable<T>,
        equality_comparable<>
    >>; 

有了这个和你对sum的定义,我可以做:

std::function<int(FwdIter<int>, FwdIter<int>)> f = sum<int>{};
std::vector<int> v = {1, 2, 3, 4, 5};
std::cout << f(v.begin(), v.end()) << std::endl; // prints 15

在您的test<T>中,您可以根据需要拥有一个std::function<T(FwdIter<T>, FwdIter<T>)>成员。

我试图研究另一种解决方案。

本质上,用户函数被包装在一个持有者持有者中,该持有者将函数签名固定为 T(const std::vector<T>&) 。关于@Barry的解决方案(我接受的解决方案),这不需要外部库。但是,由于在运行时构造矢量对象,它会遇到性能问题。此外,更重要的是,正如@Barry所指出的,该解决方案对T施加了人为的要求(例如T必须是可复制的)。

是这样的:

template <typename T,typename F>
class holder
{
public:
    holder(F f) : f_(f) { }
    T operator()(const std::vector<T>& v) const
    {
        return f_(v.begin(), v.end());
    }
private:
    F f_;
};
template <typename T>
class test_v2
{
public:
  template <typename F>
  void set(F f)
  {
    f_ = holder<T,F>(f);
  }
  template <typename I>
  T call(I first, I last) const
  {
    return f_(std::vector<T>(first, last));
  }
private:
  std::function<T(const std::vector<T>&)> f_;
};

为什么不启动函子,如下所示:

template <typename T>
class test
{
public:
  template <typename I>
  auto call(I first, I last) const
   -> decltype(T()(first, last))
  {
    return T()(first, last);
  }
};

并使用它:

test<sum<double>> t;

现场示例