我承认我很难为此提出合理的描述。我想不出一个能够准确描述我正在寻找什么的好词。也许这可以称为切片迭代器。
让我说我有这样的事情:
struct S
{
int i;
char *s;
float f;
};
std::vector<S> v(10);
我正在寻找的是一种构造迭代器的方法,它指向S
的成员。我希望能够将其传递给类似std::min_element
的内容,而无需在每种情况下创建谓词。可能看起来像这样的东西:
std::min_element(slicing_iterator(v.begin(), S::f), slicing_iterator(v.end(), S::f));
我可以使用任何模板技巧来实现这一目标吗?或者它可能已经在Boost或其他一些库中的某个地方完成了?
答案 0 :(得分:13)
如果你正在寻找一个将S转换成S :: f的迭代器,那肯定可以使用boost来实现(不可能是什么?):
std::cout << *std::min_element(
boost::make_transform_iterator(v.begin(), boost::bind(&S::f, _1)),
boost::make_transform_iterator(v.end(), boost::bind(&S::f, _1))
) << '\n';
但是如果你正在寻找其S :: f在向量中最小的S,则谓词是最合理的方法。
答案 1 :(得分:2)
如果您不想为每种情况创建一个谓词函数,我建议不要寻找切片运算符,而是将谓词实现为lambda函数(使用Boost或C ++ 0x)。在这里您可以找到详细的解释
http://www.codeproject.com/KB/cpp/Sort.aspx
(约为std::sort
,但std::min_element
中的比较同样适用。)
答案 2 :(得分:2)
这样的事情会起作用吗?
#include <algorithm>
#include <iostream>
#include <vector>
struct S
{
int i;
float f;
S() : i(0), f(0.0f) {}
S(int i_, float f_) : i(i_), f(f_) {}
};
template <typename Iterator, typename T, typename M>
class SlicingIterator : public std::iterator<typename Iterator::iterator_category,M>
{
private:
Iterator m_it;
M T::*m_m;
public:
SlicingIterator(const Iterator& it, M T::*m)
: m_it(it), m_m(m)
{}
const M operator*() const
{
return (*m_it).*m_m;
}
bool operator!=(const SlicingIterator& rhs) const
{
return m_it != rhs.m_it;
}
SlicingIterator& operator++()
{
++m_it;
return *this;
}
bool operator<(const SlicingIterator& rhs) const
{
return m_it < rhs.m_it;
}
};
template <typename Iterator, typename T, typename M>
SlicingIterator<Iterator,T,M> slicing_iterator(const Iterator& it, M T::*m)
{
return SlicingIterator<Iterator,T,M>(it, m);
}
int main()
{
std::vector<S> vec;
vec.push_back(S(23,9));
vec.push_back(S(17,10));
std::copy(slicing_iterator(vec.begin(), &S::f), slicing_iterator(vec.end(), &S::f), std::ostream_iterator<float>(std::cout, " "));
return 0;
}
答案 3 :(得分:2)
除了已经建议的内容之外,您可能会像代码示例那样完成它。
示例:
template< class IterT, class ObjT, class MemberT >
class slicing_iterator;
template< class IterT, class ObjT, class MemberT >
inline bool operator==(
const slicing_iterator<IterT,ObjT,MemberT>& a,
const slicing_iterator<IterT,ObjT,MemberT>& b
);
template< class IterT, class ObjT, class MemberT >
inline bool operator!=(
const slicing_iterator<IterT,ObjT,MemberT>& a,
const slicing_iterator<IterT,ObjT,MemberT>& b
);
template< class IterT, class ObjT, class MemberT >
class slicing_iterator
{
IterT m_iter;
MemberT ObjT::* m_member;
public:
slicing_iterator( IterT iter, MemberT ObjT::*member ) :
m_iter(iter), m_member(member)
{
}
slicing_iterator& operator++() { ++m_iter; return *this; }
slicing_iterator& operator--() { --m_iter; return *this; }
MemberT& operator*() { return static_cast<ObjT&>(*m_iter).*m_member; }
const MemberT& operator*() const { return static_cast<const ObjT&>(*m_iter).*m_member; }
MemberT* operator->() { return &m_iter->*m_member; }
const MemberT* operator->() const { return &m_iter->*m_member; }
private:
friend bool operator== <IterT,ObjT,MemberT>(
const slicing_iterator<IterT,ObjT,MemberT>& a,
const slicing_iterator<IterT,ObjT,MemberT>& b
);
friend bool operator!= <IterT,ObjT,MemberT>(
const slicing_iterator<IterT,ObjT,MemberT>& a,
const slicing_iterator<IterT,ObjT,MemberT>& b
);
};
template< class IterT, class ObjT, class MemberT >
inline bool operator==(
const slicing_iterator<IterT,ObjT,MemberT>& a,
const slicing_iterator<IterT,ObjT,MemberT>& b
)
{
return a.m_iter == b.m_iter && a.m_member == a.m_member;
}
template< class IterT, class ObjT, class MemberT >
inline bool operator!=(
const slicing_iterator<IterT,ObjT,MemberT>& a,
const slicing_iterator<IterT,ObjT,MemberT>& b
)
{
return a.m_iter != b.m_iter || a.m_member != a.m_member;
}
template< class IterT, class ObjT, class MemberT >
inline slicing_iterator<IterT,ObjT,MemberT>
make_slicing_iterator( IterT iter, MemberT ObjT::*member )
{
return slicing_iterator<IterT,ObjT,MemberT>( iter, member );
}
struct S
{
int i;
char *s;
float f;
};
int main(void)
{
std::vector<S> v(10);
std::min_element(
make_slicing_iterator(v.begin(), &S::f),
make_slicing_iterator(v.end(), &S::f)
);
return 0;
}
起初我没有注意到 - 它看起来与@Stuart Golodetz建议的类似,但优点是运营商&lt;不必为迭代器类型定义(例如std :: list :: iterator)。它使这种实现具有普遍性。