以迭代器为参数的 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
),但不适用于其他容器(例如,像以上变量 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
进行编译
非常感谢。
为什么不激发仿函数呢,比如:
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;
你真正想要的是能够构建一个:
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_;
};
我想编写一个 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
),但不适用于其他容器(例如,像以上变量 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
进行编译非常感谢。
为什么不激发仿函数呢,比如:
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;
你真正想要的是能够构建一个:
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_;
};