0
votes

I tried to use the excellent answers I got in my previous question to understand this problem, but I do not understand why this code does not compile.

#include <iostream>
#include <ostream>
#include <string>
#include <cstdlib>
#include <vector>
#include <memory>

template <typename T,
          template <typename ELEM,
                    typename = std::allocator<ELEM> >
                    class CONT = std::deque>
class Stack {

public:
  typedef typename CONT<T>::size_type size_type;

  private:
    CONT<T> elems;         // elements

  public:
    void push(T const&);   // push element
    void pop();            // pop element
    T top() const;         // return top element
    bool empty() const {   // return whether the stack is empty
        return elems.empty();
    }

       size_type size();
};

template <typename T, template <typename,typename> class CONT>
void Stack<T,CONT>::push (T const& elem)
{
    elems.push_back(elem);    // append copy of passed elem
}

template<typename T, template <typename,typename> class CONT>
void Stack<T,CONT>::pop ()
{
    if (elems.empty()) {
        throw std::out_of_range("Stack<>::pop(): empty stack");
    }
    elems.pop_back();         // remove last element
}

template <typename T, template <typename,typename> class CONT>
T Stack<T,CONT>::top () const
{
    if (elems.empty()) {
        throw std::out_of_range("Stack<>::top(): empty stack");
    }
    return elems.back();      // return copy of last element
}


template<typename T,
template<typename, typename= std::allocator<T> > class CONT>
typename Stack<T, CONT>::size_type Stack<T, CONT>::size()
{
  return elems.size();
}

template <typename T,
          template <typename ELEM, typename = std::allocator<ELEM> > class CONT>
static inline void Pout(const CONT<T>& container)

{

  typedef typename CONT<T >::size_type size_type;

  size_type idx = 0;
  size_type sz = CONT<T>::size();

  CONT<T> temp = container;
  std::cout << '[';
  while (idx < sz)
  {
    std::cout << temp.top();
    temp.pop();
    idx++;
    if (idx == sz) break;
    std::cout << ", ";
  }
  std::cout << "]";
}


int main()
{
  try {
    Stack<int,   std::vector > vStack;
    //...
    vStack.push(42);
    vStack.push(7);

    Pout<Stack<int,   std::vector > >(vStack);
  }
  catch (std::exception const& ex) {
    std::cerr << "Exception: " << ex.what() << std::endl;
  }
}

I get the compiler error using g++ 4.3.4:

stack8test.cpp: In function int main():
stack8test.cpp:28: error: no matching function for call to Pout(Stack<int, std::vector>&)
make: *** [stack8test.o] Error 1

I will appreciate help.

I made changes to comment out the function call Pout >(vStack) and to print the contents of vStack to std::cout. Here is the new code. It compiles and works as expected:

#include <iostream>
#include <ostream>
#include <string>
#include <cstdlib>
#include <vector>
#include <memory>

#include <deque>
#include <stdexcept>

template <typename T,
          template <typename ELEM,
                    typename = std::allocator<ELEM> >
                    class CONT = std::deque>
class Stack {

public:
  typedef typename CONT<T>::size_type size_type;
  typedef typename CONT<T>::value_type value_type;

  private:
    CONT<T> elems;         // elements

  public:
    void push(T const&);   // push element
    void pop();            // pop element
    T top() const;         // return top element
    bool empty() const {   // return whether the stack is empty
        return elems.empty();
    }

    size_type size();
    void Pout();
};

template <typename T, template <typename,typename> class CONT>
void Stack<T,CONT>::push (T const& elem)
{
    elems.push_back(elem);    // append copy of passed elem
}

template<typename T, template <typename,typename> class CONT>
void Stack<T,CONT>::pop ()
{
    if (elems.empty()) {
        throw std::out_of_range("Stack<>::pop(): empty stack");
    }
    elems.pop_back();         // remove last element
}

template <typename T, template <typename,typename> class CONT>
T Stack<T,CONT>::top () const
{
    if (elems.empty()) {
        throw std::out_of_range("Stack<>::top(): empty stack");
    }
    return elems.back();      // return copy of last element
}


template<typename T,
template<typename, typename= std::allocator<T> > class CONT>
typename Stack<T, CONT>::size_type Stack<T, CONT>::size()
{
  return elems.size();
}


template <typename T,
template<typename, typename = std::allocator<T> > class CONT>
void Stack<T, CONT>::Pout()
{

  size_type idx = 0;
  size_type sz = size();

  CONT<T>  temp(elems); // make a temp copy of the underlying container and print the temp, since printing is destructive. Note that the underlying CONT must already support copy constructor.

  std::cout << std::endl << '[';
  while (idx < sz)
  {
    std::cout << temp.back();
    temp.pop_back();
    idx++;
    if (idx == sz) break;
    std::cout << ", ";
  }
  std::cout << "]" << std::endl;;

}
template <typename T,
          template <typename ELEM, typename = std::allocator<ELEM> > class CONT>
void Pout(const CONT<T>& container)

{

  typedef typename CONT<T >::size_type size_type;

  size_type idx = 0;
  size_type sz = CONT<T>::size();

  CONT<T> temp = container;
  std::cout << '[';
  while (idx < sz)
  {
    std::cout << temp.top();
    temp.pop();
    idx++;
    if (idx == sz) break;
    std::cout << ", ";
  }
  std::cout << "]";
}


int main()
{
  try {
    Stack<int,   std::vector > vStack;
    //...
    vStack.push(42);
    vStack.push(7);

//    Pout<Stack<int,   std::vector > >(vStack);
    vStack.Pout();
    std::cout << "vStack = [" << vStack.top(); vStack.pop();
    std::cout << ", " << vStack.top() << "]" << std::endl; vStack.pop();
  }
  catch (std::exception const& ex) {
    std::cerr << "Exception: " << ex.what() << std::endl;
  }
}

The compiler output is:

g++ -O2 -g -Wall -c -o stack8test stack8test.cpp

Running the program, I got:

./stack8test 
vStack = [7, 42]

My real problem is finding the right syntax for the function template Pout to print out the contents of my class template Stack. To clarify, my intent is to implement a class template Stack as a container of elements of type T. I want to implement Stack in terms of an std container of type std::vector or std::deque, or even std::list.

I called Pout as :

Pout<int, Stack<int, std::vector>>(vStack);

But the compiler still says:

stack8test.cpp: In function int main():
stack8test.cpp:137: error: no matching function for call to Pout(Stack<int, std::vector>&)
make: *** [stack8test.o] Error 1

UPDATE: As a work around for my original original problem of a global (i.e. non-member) function for print the contents of my Stack to std::cout, I have defined Pout() as a member function. It compiles and works as expected. Finding the right syntax for the global function remains a challenge.

1
When you use std::deque, you should (also) include the header <deque>.dyp
Sorry about not commenting earlier. I have been out sick.user2975538
Sorry about not commenting earlier. I have been out sick. I am not sure you understand my design: Stack is a class template container that can be implemented with either one of the STL containers: vector or deque. I think it is a reasonable design. @Mikhailuser2975538

1 Answers

2
votes

You got things too complicated. You should let compiler deduce as much information for you as possible and instead of writing

template <typename T,
      template <typename ELEM, typename = std::allocator<ELEM> > class CONT>
static inline void Pout(const CONT<T>& container)

simply write

template <class CONT>
static inline void Pout(const CONT& container)

This is how it is done in STL. If you need to access underlying type of the container, again, use the STL approach and add the value_type typedef to the class:

class Stack {
public:
  ...
  typedef T value_type;
  ...
}

You can then access it in the function as CONT::value_type. However, you don't even use this information in Pout function.

Some other errors:

  • Mark size function as const as it should be
  • Do not use static inline specifiers for you functionы unless you're 100% sure you know what you're doing. Probably, you're not.

Code compiles after fixing these errors, but the overall design is quite poor.