我如何返回包装容器的反向适配器?

时间:2013-02-12 15:14:09

标签: c++ c++11 visual-studio-2012

我有一个类,它有一个deque,它用作堆栈(可能是一个向量,恰好选择了deque)。

无论如何,我希望允许消费者迭代堆栈的内容(std :: stack不能做的事情)。我目前正在使用push_back()将项目推送到堆栈中,因此如果在前向排序中迭代内容,则从堆栈的底部到顶部。

我更喜欢以相反的顺序公开事物,因此使用for(auto e:thestack)在堆栈上迭代以自上而下的方式工作。

我发现C++11 reverse range-based for-loop显示了一些解决方案,用于反转新的for-loop语法(以及基于范围的算法)的迭代排序。

我不清楚如何提供一个简单的机制,让我的用户可以访问这个自动反转的双端队列。

e.g。没有任何实际的努力,我可以简单地允许const&访问底层双端队列:

  const std::deque<T> & GetStack() const { return m_stack; }

消费者可以负责倒车:

  for (auto e : reverse(m_toolstack.GetStack()))

在这里,我试图使用以下解决方案进行反向:

template<class Fwd>
struct reverser_generic 
{
    Fwd &fwd;
    reverser_generic(Fwd& fwd_): fwd(fwd_) {}
    typedef std::reverse_iterator<typename Fwd::iterator> reverse_iterator;
    reverse_iterator begin() { return reverse_iterator(std::end(fwd)); } 
    reverse_iterator end() { return reverse_iterator(std::begin(fwd)); } 
};

template<class Fwd>
struct reverser_special
{
    Fwd &fwd;
    reverser_special(Fwd& fwd) : fwd(fwd) { }
    auto begin() -> decltype(fwd.rbegin()) { return fwd.rbegin(); } 
    auto end() -> decltype(fwd.rend()) { return fwd.rend(); } 
};

template<class Fwd>
auto reverse_impl(Fwd& fwd, long) -> decltype(reverser_generic<Fwd>(fwd))
{ 
    return reverser_generic<Fwd>(fwd);
}

template<class Fwd>
auto reverse_impl(Fwd& fwd, int) -> decltype(fwd.rbegin(), reverser_special<Fwd>(fwd))
{ 
    return reverser_special<Fwd>(fwd);
}

template<class Fwd>
auto reverse(Fwd&& fwd) -> decltype(reverse_impl(fwd,int(0))) 
{
    static_assert(!(std::is_rvalue_reference<Fwd&&>::value), "Cannot pass an rvalue reference to reverse()");
    return reverse_impl(fwd,int(0));
}

以上所有内容都使用VS2012正确编译和运行(感谢Jive Dadson等人的解决方案)。

然而,在我的堆栈外观中,我真的想简单地总是返回底层容器的反面,但我不明白如何以合理的方式这样做:

auto GetContents() const -> decltype(reverse(m_stack)) { return reverse(m_stack); }

以上错误,表明m_stack未知。 this-&gt; m_stack同样未知。

我怎样才能回复“不管我的成员m_stack的反面是什么”?

注意,一旦回答了这个问题,我还需要“如何返回反转(m_stack)的decltype的const&amp;?

1 个答案:

答案 0 :(得分:1)

GetContents声明之前是m_stack的声明吗?

后期指定的返回类型中的名称必须遵守与函数签名其余部分中的名称相同的规则,即它们不能引用尚未声明的类成员:

struct X
{
    auto f() -> decltype(m_x) { return m_x; }  // ERROR
    int m_x;
    auto g() -> decltype(m_x) { return m_x; }  // OK
};

要使其有效,请使用std::declval来引用该类型(这意味着如果您从{{1}更改GetContents的类型,则必须更新m_stack的签名}} std::deque}或确保std::vector在您引用之前已声明。