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

C++ member function with iterator as parameter

我想编写一个 class test 能够存储一个函数,该函数能够遍历由 classic [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

进行编译

非常感谢。

为什么不激发仿函数呢,比如:

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;

Live example

你真正想要的是能够构建一个:

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

其中 FwdIter<T> 是某种类型擦除的 class,满足 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>)> 成员。

我已尝试研究替代解决方案。

本质上,用户函数被包装在一个 holder holder 中,它将函数签名固定为 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_;
};