如何编写可以接受堆栈或队列的函数模板?

时间:2011-01-27 20:54:44

标签: c++ templates stl function-templates

我正在实现完全相同的四种算法,除了他们使用的数据结构 - 两次使用priority_queue,一次使用stack,最后一次使用{{ 1}}。它们相对较长,所以我想只有一个函数模板接受容器类型作为模板参数,然后让每个算法用适当的参数调用该模板,如下所示:

queue

我已经设法通过基于template <class Container> void foo(/* args */) { Container dataStructure; // Algorithm goes here } void queueBased(/* args */) { foo<queue<Item> >(/* args */); } void stackBased(/* args */) { foo<stack<Item> >(/* args */); } priority_queue的实现做到了这一点,但我不能对基于stack的算法做同样的事情,因为它使用了访问最重要元素的不同名称(queue而不是front( ))。我知道我可以专门针对这种情况使用模板,但后来我会有大量的重复代码(我正在努力避免这种情况)。

实现这一目标的最佳方法是什么?我的第一个本能是为队列创建一个包装类,它添加了一个等同于top( )的{​​{1}}操作,但我一直在读这个子类化STL类是禁止的。那我该怎么办呢?

5 个答案:

答案 0 :(得分:7)

您可以在容器适配器的类型上写一个非成员top函数:

template <typename T>
T& top(std::stack<T>& s) { return s.top(); }

template <typename T>
T& top(std::queue<T>& q) { return q.front(); }

// etc.

如果您实际使用带容器适配器的不同序列容器(通过其Sequence模板参数),则需要适当修改重载以处理它。

直接使用序列容器(例如std::vector)而不是使用其中一个序列适配器可能更直接。

答案 1 :(得分:2)

您可以使用部分特化来选择正确的方法:

template<class Container>
struct foo_detail {
  static typename Container::value_type& top(Container &c) { return c.top(); }
  static typename Container::value_type const& top(Container const &c) { return c.top(); }
};
template<class T, class Underlying>
struct foo_detail<std::queue<T, Underlying> > {
  typedef std::queue<T, Underlying> Container;
  static typename Container::value_type& top(Container &c) { return c.front(); }
  static typename Container::value_type const& top(Container const &c) { return c.front(); }
};

template<class Container>
void foo(/* args */)
{
    Container dataStructure;
    // Use foo_detail<Container>::top(dataStructure) instead of dataStructure.top().
    // Yes, I know it's ugly.  :(
}

答案 2 :(得分:1)

您可以在不使用继承的情况下围绕std::queue创建包装器;事实上,继承将是错误的工具,因为你试图装饰一个queue而不是精炼扩展 queue。这是一种可能的实现方式:

template <typename QueueType>
class QueueWrapper {
public:
    explicit QueueWrapper(const QueueType& q) : queue(q) {
        // Handled in initializer list
    }

    typedef typename QueueType::value_type value_type;

    value_type& top() {
        return queue.front();
    }
    const value_type& top() const {
        return queue.front();
    }

    void pop() {
        queue.pop();
    }
private:
    QueueType queue;
};

希望这有帮助!

答案 3 :(得分:0)

queuepriority_queuestack都是容器适配器;它们是底层容器的包装器(默认情况下,dequequeuestackvectorpriority_queuevector

由于dequelist和{{1}}(“真正的”容器类)共享大多数方法,因此您可以删除中间人并使用这些类。

请记住, public 继承对于STL容器来说不是一个好主意; 私有继承是可以的(也可能是你想要的)。

答案 4 :(得分:-1)

front()top()特定于某些类型的容器,但所有STL容器都支持*begin()