简体   繁体   English

如何编写 c++ function 什么可以返回迭代器或 reverse_iterator

[英]How to write a c++ function what can return either iterator or reverse_iterator

As far as I can tell in c++ there is no common base class that covers both iterator and reverse_iterator.据我所知,在 c++ 中没有涵盖迭代器和 reverse_iterator 的通用基础 class。

The only suggestion I have seen so far is to get around this using templates ( How to write a function that takes an iterator or collection in a generic way? )到目前为止我看到的唯一建议是使用模板来解决这个问题( 如何编写一个 function 以通用方式采用迭代器或集合?

However this solution doesn't seem to work for me.但是,此解决方案似乎对我不起作用。

class MyClass
{
    template<typename Iter> Iter* generate_iterator(...params...)
    {
        //returns either a vector::iterator or vector::reverse_iterator
    }
    template<typename Iter> void do_stuff(Iter *begin, Iter *end)
    {
        //does stuff between elements specified by begin and end
        //I would like this function to remain agnostic of which direction it is working in!
    }
    void caller()
    {
        //I would like this function to remain agnostic of which direction it is working in too...
           do_stuff(generate_iterator(blah),generate_iterator(foo));
    }
};

In this case, generate_iterator() cannot be used as desired because the compiler complains "generate_iterator is not a member of class MyClass" presumably because I haven't specified it (which I can't in practice as caller should be agnostic of the iterator type).在这种情况下,generate_iterator() 不能按需要使用,因为编译器抱怨“generate_iterator 不是 class MyClass 的成员”大概是因为我没有指定它(实际上我不能因为调用者应该不知道迭代器类型)。

Can anyone help?任何人都可以帮忙吗? Thanks in advance!提前致谢!

edit : as Mark B pointed out generate_iterator must return a pointer - now corrected编辑:正如 Mark B 指出的,generate_iterator 必须返回一个指针——现在更正了

update : just started using this http://thbecker.net/free_software_utilities/type_erasure_for_cpp_iterators/start_page.html and it seems to work...更新:刚开始使用这个http://thbecker.net/free_software_utilities/type_erasure_for_cpp_iterators/start_page.html它似乎工作......

You can create your own iterator class that knows how to go both directions.您可以创建自己的迭代器 class 知道如何 go 双向。 Encapsulate both types of iterator and internally select whichever one you were initialized with.封装这两种类型的迭代器和内部 select ,无论您使用哪一种进行初始化。

Here's a start:这是一个开始:

template<typename Container>
class BiIterator
{
public:
    BiIterator(Container::iterator i) : m_fwd(i), m_isforward(true) {}
    BiIterator(Container::reverse_iterator i) : m_rev(i), m_isforward(false) {}
    bool operator==(const BiIterator & left, const BiIterator & right);
    Container::value_type & operator*()
    {
        if (m_isforward)
            return *m_fwd;
        return *m_rev;
    }
    const Container::value_type & operator*() const;
    BiIterator & operator++()
    {
        if (m_isforward)
            ++m_fwd;
        else
            ++m_rev;
        return *this;
    }
private:
    Container::iterator         m_fwd;
    Container::reverse_iterator m_rev;
    bool                        m_isforward;
};

In C++ you can't write a function that returns two different types.在 C++ 中,您不能编写返回两种不同类型的 function。 In your template case it will return one or the other depending on the instantiation.在您的模板情况下,它将根据实例化返回一个或另一个。 You could possibly return a base pointer to a polymorphic iterator but that would cause me to ask what you're really trying to do here.你可能会返回一个指向多态迭代器的基指针,但这会让我问你在这里真正想要做什么。 Even the standard containers don't try to do that: They have begin and rbegin to distinguish properly.即使是标准容器也不会尝试这样做:它们已经beginrbegin正确区分。 I would suggest having two separate functions that each do the right thing and return one type of iterator or the other as context dictates.我建议有两个独立的函数,每个函数都做正确的事情,并根据上下文的指示返回一种类型的迭代器或另一种。

As a side, note that you can't implicitly determine a template instantiation of a type that's only used for the return type of a function.另外,请注意,您不能隐式确定仅用于 function 的返回类型的类型的模板实例化。

By using boost tuple and boost any, your problem can be easily solved.通过使用 boost tuple 和 boost any,你的问题可以很容易地解决。 I wrote a example by using boost::any, see below:我使用 boost::any 写了一个例子,见下文:

#include <boost/any.hpp>
using boost::any_cast;
#define MSG(msg) cout << msg << endl;
boost::any getIterator(std::vector<int>& vec, bool bReverse)
{
    if(!bReverse)
        return boost::any(vec.begin());
    else
        return boost::any(vec.rbegin());
}

int main() 
{
    std::vector<int> myvec;
    myvec.push_back(1);
    myvec.push_back(2);
    myvec.push_back(3);


    typedef std::vector<int>::iterator vecIter;
    typedef std::vector<int>::reverse_iterator vecRIter;
    try
    {
        boost::any iter  = getIterator(myvec, false);
        boost::any iter2 = getIterator(myvec, true);
        vecIter  it1 = any_cast<vecIter>(iter);
        vecRIter it2 = any_cast<vecRIter>(iter2);
        MSG(*it1);//output 1
        MSG(*it2);//output 3
        return true;
    }
    catch(const boost::bad_any_cast &)
    {
        return false;
    }
}

Use boost::variant or boost::any .使用boost::variantboost::any

boost::variant< reverse_iterator, iterator >
generate_iterator(...) {
  if(...) return iterator();
  else return reverse_iterator();
}

// user code
boost::variant< reverse_iterator, iterator > v = generate_iterator();

if(reverse_iterator* it = boost::get<reverse_iterator>(v))
  ...;
else if(...)
  ...;

Although the variant is better accessed through a visitor.尽管通过访问者可以更好地访问该variant

The downside is that you need some boiler plate to extract the proper type and is exactly the reason why something like any_iterator might be a more sensible choice.缺点是您需要一些样板来提取正确的类型,这正是为什么像any_iterator这样的东西可能是更明智的选择的原因。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM