我想编写一个类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
),但不适用于其他容器(例如,类似于以上变量v
和l
):
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
进行编译非常感谢。
答案 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;