迭代器“指向”到对象的成员

发布于 2024-11-03 21:41:51 字数 466 浏览 0 评论 0原文

我承认我很难对此做出合理的描述。我想不出一个好的术语来准确描述我正在寻找的东西。也许这可以称为切片迭代器

假设我有这样的东西:

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 或其他库中完成了?

I admit I had difficulties coming up with a reasonable description for this. I cannot think of a good term that would describe precisely what I'm looking for. Perhaps this could be called a slicing iterator.

Let's say I have something like this:

struct S
{
    int i;
    char *s;
    float f;
};

std::vector<S> v(10);

What I'm looking for is a way to construct an iterator, that would point to a member of S. I'd like to be able to pass it to something like std::min_element without creating a predicate in each case. Something that might look like this:

std::min_element(slicing_iterator(v.begin(), S::f), slicing_iterator(v.end(), S::f));

Is there any template trick that I could use to achieve this? Or perhaps it's already done somewhere in Boost or some other library?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

彩扇题诗 2024-11-10 21:41:51

如果您正在寻找一个将 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';

test: https://ideone.com/jgcHr

但是,如果您正在寻找 S::f 是向量中最小的 S,则谓词是最合理的方法。

If you're looking for an iterator that converts S into its S::f, this could certainly be done using boost (what can't be?):

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';

test: https://ideone.com/jgcHr

But if you're looking for the S whose S::f is the smallest in the vector, the predicate is the most reasonable approach.

尐偏执 2024-11-10 21:41:51

如果您不想为每种情况创建谓词函数,我建议不要寻找切片运算符,而是将谓词实现为 lambda 函数(使用 Boost 或 C++0x)。在这里您可以找到详细的解释

http://www.codeproject.com/KB/cpp/ Sort.aspx

(这是关于 std::sort 的,但 std::min_element 中的比较同样有效。)

If you don't want to create a predicate function for each case, I would suggest not to look for a slicing operator, but to implement your predicate as a lambda function (either using Boost or C++0x). Here you will find a detailed explanation

http://www.codeproject.com/KB/cpp/Sort.aspx

(this is about std::sort, but the comparison in std::min_element works equally.)

会傲 2024-11-10 21:41:51

像这样的东西可以完成工作吗?

#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;
}

Will something like this do the job?

#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;
}
救星 2024-11-10 21:41:51

除了已经建议的内容之外,您还可以像代码示例那样几乎完全一样地进行操作。

示例:

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 建议的类似,但优点是运算符<不必为迭代器类型定义(例如 std::list::iterator)。它使这个实现具有普遍性。

In addition to what is already suggested you may do it almost exactly like your code sample does.

Example:

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;
}

At first I didn't notice - it looks similar to what @Stuart Golodetz suggested but the advantage is that operator< doesn't have to be defined for iterator type (e.g. std::list::iterator). It makes this implementation universal.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文