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

时间:2015-01-06 11:38:15

标签: c++ templates functor

我想编写一个类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

进行编译

非常感谢。

3 个答案:

答案 0 :(得分:2)

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

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>)>成员。

答案 1 :(得分:1)

我尝试过另一种解决方案。

基本上,用户功能被包装在一个持有者持有者中,它将功能签名固定到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_;
};

答案 2 :(得分:0)

为什么不改用仿函数,例如:

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