Given this example class template:
template<typename T>
class Stack {
T * data;
int size;
int nextIndex;
public:
Stack(int size = 100);
Stack(const Stack& stack);
~Stack();
Stack& operator=(const Stack& s);
void push(const T& t);
void pop();
T& top();
const T& top() const;
int getSize() const;
class Full {
};
class Empty {
};
};
template<typename T>
void Stack::push(const T& t) {
if (nextIndex >= size) {
throw Full();
}
data[nextIndex++] = t;
}
template<typename T>
void Stack::pop() {
if (nextIndex <= 0) {
throw Empty();
}
nextIndex--;
}
Is it ok the part of the implementaion of the push and pop methods?
I don't understand if I need to write void Stack<T>::push(const T& t) instead of void Stack::push(const T& t) (and the same for the pop method).
NOTE: Eclipse (according to C++11) gives me the next error:
Member declaration not found
because of these lines:
void Stack::push(const T& t) {
void Stack::pop() {
The part of the implementaion of push method and pop method it's ok? I don't understand if I need to write void Stack::push(const T& t) instead void Stack::push(const T& t) (and the same for pop method).
You need to use
template <typename T>
void Stack<T>::push(const T& t) { ... }
template <typename T>
void Stack<T>::pop() { ... }
The name Stack is the same as Stack<T> inside the class template definition when it is used as a typename. Outside the class template definition, you have to supply the template parameter explicitly.
Both push() and pop() are (non-template) member functions of the Stack class template. Since this class template, Stack, is parameterized by a type template parameter (i.e.: T), so are those member functions as well.
Therefore, the implementation of those member functions needs a type template parameter:
template<typename A>
void Stack<A>::push(const A& t) { ... }
template<typename B>
void Stack<B>::pop() { ... }
Note that the name of the template parameter is actually irrelevant (A and B above).
Note as well that the name of the class template Stack not followed by any template arguments inside the body of its definition is equivalent to the class template with its template parameter as the template argument, i.e.: Stack<T>.
Related
Well, I'm trying to implement the copy_and_swap idiom on my first Stack in C++, for that I need to create a swap function and this swap function needs to be a friend function, I tried to do it by this way:
template <class T>
class Stack {
private:
int top;
T* a;
int MAX;
public:
Stack(int MAX);
Stack(Stack<T>& s);
bool push(T x);
bool pop();
T peek();
bool isEmpty();
friend void swap(Stack<T>& f, Stack<T>& s);
~Stack();
};
template <class T>
void Stack<T>::swap(Stack<T>& f, Stack<T>& s){
//I will put something where yet.
}
But, the VSCode says this about the swap function: class model "Stack " does not have a "swap" member (I translate for English, my VSCode runs in Portuguese).
How I can do that without receiving this error?
Your friend function is not template, so to define outside, you would have to define the non template function for each type (which seems impracticable):
void swap(Stack<int>& lhs, Stack<int>& rhs){/*..*/}
void swap(Stack<char>& lhs, Stack<char>& rhs){/*..*/}
void swap(Stack<MyType>& lhs, Stack<MyType>& rhs){/*..*/}
Simpler (and better IMO) is to define inside the class.
template <class T>
class Stack {
// ...
friend void swap(Stack& lhs, Stack& rhs) { /*..*/ };
};
Alternative is to make the friend function template:
template <class T> class Stack;
template <class T> void swap(Stack<T>&, Stack<T>&);
template <class T>
class Stack {
// ...
friend void swap<>(Stack& f, Stack& s); // Only the specialization is friend
};
template <class T>
void swap(Stack<T>& lhs, Stack<T>& rhs){ /**/ }
I am just working on my school homework, and I am interested if C++ could create specialized destructor for pointers. I know that this is not good practice, but because of performance, I want to do it this way. Also because I am curious about it. So lets say, that we have this class:
template<typename T,int(*comp)(const T& first, const T& second)>
class BinomialHeapLite
{
private:
class Node
{
Node* next;
T instance;
}
Node* top;
public:
~BinomialHeapLite();
}
Now I want destructor, that delete just node, if is T only type and delete also inner instance, if is T pointer..
template<typename T, int(*comp)(const T& first, const T& second)>
BinomialHeapLite<T,comp>::~BinomialHeapLite()
{
//some code
delete this->top;
}
template<typename T, int(*comp)(const T* &first, const T* &second)>
BinomialHeapLite<T*,comp>::~BinomialHeapLite()
{
//some code
delete this->top->instance;
delete this->top;
}
But this give me "invalid use of incomplete type". I also want to use pure C++11, because I want to be independent to another libraries (also standards libraries), moreover that libraries are not permitted in out system.
Is something like this possible in pure C++?
You're giving your BinomialHeapLite class a responsibility that it shouldn't have: cleaning up instance if it's a heap-allocated pointer.
That burden should be on the user of your class: what if he is already calling delete in its own code? What if the object is supposed to be reused after your BinomialHeapLite is destroyed?
All your class should do is provide a generic container that manages its own memory. For that task, your should also use smart pointers (std::unique_ptr in this case):
template<typename T,int(*comp)(const T& first, const T& second)>
class BinomialHeapLite
{
private:
class Node
{
std::unique_ptr<Node> next;
T instance;
}
std::unique_ptr<Node> top;
}
You won't need an hand-written destructor then. Refer to the "rule of three/five/zero" for more information.
If you really want to implement your flawed/unconventional design, you could use a partially specialized helper struct that calls delete if its type is a pointer:
template <typename T>
struct dtor_helper
{
static void do_it(T&&){}
};
template <typename T>
struct dtor_helper<T*>
{
static void do_it(T* x){ delete x; }
};
template<typename T, int(*comp)(const T& first, const T& second)>
BinomialHeapLite<T,comp>::~BinomialHeapLite()
{
//some code
dtor_helper<T>::do_it(this->top->instance);
delete this->top;
}
wandbox example
You can not partially specialize a member function. But you can partially specialize a class template:
template <class T>
struct Deallocator{
template <class Node>
static void Deallocate(const Node &node){}
};
template <class T>
struct Deallocator<T *>{
template <class Node>
static void Deallocate(const Node &node){}
};
template<typename T, int(*comp)(const T& first, const T& second)>
BinomialHeapLite<T,comp>::~BinomialHeapLite()
{
//some code
Deallocator<T>::Deallocate(top);
}
Or overload a function :
template<typename T,int(*comp)(const T& first, const T& second)>
class BinomialHeapLite
{
private:
struct Node // a little change here
{
Node* next;
T instance;
};
Node* top;
template <class Ty>
void deallocate(Ty *) {}
template <class Ty>
void deallocate(Ty &) {}
public:
~BinomialHeapLite();
};
template<typename T, int(*comp)(const T& first, const T& second)>
BinomialHeapLite<T,comp>::~BinomialHeapLite()
{
//some code
deallocate(top->instance);
}
For my course, I'm asked to create a Stack class that stores its elements in a STL container (but not the STL stack container).
Requirements:
must be able to store elements of an arbitrary type
every instance accepts insertions as long as the system has enough free memory
must be in namespace cop4530
must use most of the methods and operator overloads shown in header file below
(not back(), +=op, []ops)
methods/functions, etc declared in .h, and implemented in separate .hpp
I then use the stack with another program I create that changes infix notation arithmetic to postfix, and evaluates it if all the elements are comparable.
My professor gave an example header file of what this may look like, which is shown below.
Why does he use a deque pointer??
I've searched and found many cases where people adapt a STL container to a stack, but never an explanation for a STL container as a pointing to a stack. Could someone explain the benefits of this over using a non pointer, if there are any? Examples help
Example .h declaration file
#ifndef COP4530_STACK_H
#define COP4530_STACK_H
#include <iostream>
#include <deque>
namespace cop4530
{
template <typename T>
class Stack;
//----------------------------------
// Stack<T>
//----------------------------------
template <typename T>
class Stack
{
public:
// Constructor, Copy-constructor and destructor
Stack ();
Stack (const Stack<T>&);
Stack (Stack<T> &&);
~Stack ();
// member operators
Stack<T>& operator = (const Stack<T>&);
Stack<T> & operator=(Stack<T> &&);
Stack<T>& operator += (const Stack<T>&);
const T& operator [] (int) const;
T& operator [] (int);
// other methods
int size () const;
int capacity () const;
// Container class protocol
bool empty () const;
void clear ();
void push (const T&);
void push (T &&);
void pop ();
T& top ();
const T& top () const;
T& back ();
// Display methods
void print (std::ostream& os, char ofc = ' ') const;
protected:
std::deque<T> *mystack; // pointer to the stack.
//std::deque<T> mystack; //WHY NOT THIS???
} ;
// operator overloads
template < class T >
std::ostream& operator << (std::ostream& os, const Stack<T>& a);
template < class T >
bool operator == (const Stack<T>&, const Stack<T>&);
template < class T >
bool operator != (const Stack<T>&, const Stack<T>&);
template < class T >
bool operator <= (const Stack<T>&, const Stack<T>&);
#include "stack.hpp"
} // namespace cop4530
#endif
Example .hpp implementation
#ifndef COP4530_STACK_HPP
#define COP4530_STACK_HPP
//----------------------------------------
// Stack<T>:: Implementations
//----------------------------------------
// operator overloads
template <typename T>
std::ostream& operator << (std::ostream& os, const Stack<T>& s)
{
}
template <typename T>
bool operator<=(const Stack<T>& s1, const Stack<T>& s2)
{
}
template <typename T>
bool operator == (const Stack<T>& s1, const Stack<T>& s2)
{
}
template <typename T>
bool operator != (const Stack<T>& s1, const Stack<T>& s2)
{
}
// public methods
template <typename T>
Stack<T>::Stack()
//Constructor
{
}
template <typename T>
Stack<T>::Stack(const Stack<T>& source)
//Copy-constructor
{
}
template <typename T>
Stack<T>::Stack(Stack<T> && source)
{
}
template <typename T>
Stack<T>::~Stack()
// destructor
{
}
template <typename T>
Stack<T>& Stack<T>::operator = (const Stack<T>& source)
// assignment operator
{
}
template <typename T>
Stack<T>& Stack<T>::operator = (Stack<T> && source)
{
}
template <typename T>
Stack<T>& Stack<T>::operator += (const Stack<T>& source)
{
}
template <typename T>
const T& Stack<T>::operator [] (int i) const
// element operator
{
}
template <typename T>
T& Stack<T>::operator [] (int i)
// element operator
{
}
template <typename T>
bool Stack<T>::empty() const
{
}
template <typename T>
int Stack<T>::size() const
{
}
template <typename T>
void Stack<T>::push(const T& Val)
{
}
template <typename T>
void Stack<T>::push(T && Val)
{
}
template <typename T>
void Stack<T>::pop()
{
}
template <typename T>
void Stack<T>::clear()
{
}
template <typename T>
T& Stack<T>::top()
{
}
template <typename T>
const T& Stack<T>::top() const
{
}
template <typename T>
T& Stack<T>::back()
{
}
template <typename T>
void Stack<T>::print(std::ostream& os, char ofc) const
{
}
#endif
Suppose I have a list class:
template<typename T>
class list {
...
private:
class node {
...
private:
std::size_t refcount_;
// friends of node because accessing private member refcount_
friend void intrusive_ptr_add_ref(const node* p) noexcept;
friend void intrusive_ptr_release(const node* p) noexcept;
};
// friends of list because accessing private nested class node
friend void intrusive_ptr_add_ref(const node* p) noexcept;
friend void intrusive_ptr_release(const node* p) noexcept;
boost::intrusive_ptr<node> node_{new node};
};
template<typename T>
void intrusive_ptr_add_ref(const typename list<T>::node* p) noexcept
{ ... }
template<typename T>
void intrusive_ptr_release(const typename list<T>::node* p) noexcept
{ ... }
list<int> xs; // error
The code above doesn't compile. The error was undefined symbols for intrusive_ptr_add_ref(list<int>::node const*) and intrusive_ptr_release(list<int>::node const*).
I think the problem is probably that I'm declaring non-template functions as friends in list and node, but what I defined are function templates. So what's the correct way to do this?
This is one of those occasions where inline friend definitions shine:
Live On Coliru
#include <iostream>
#include <boost/intrusive_ptr.hpp>
template<typename T> class list {
class node {
std::size_t mutable refcount_;
// friends of list because accessing private nested class node
friend void intrusive_ptr_add_ref(node const* p) noexcept {
p->refcount_ += 1;
}
friend void intrusive_ptr_release(node const* p) noexcept {
if (--p->refcount_)
return;
std::cout << "freeing node " << static_cast<void const*>(p) << "\n";
}
};
boost::intrusive_ptr<node> node_{new node};
};
int main() {
list<int> xs;
}
Prints
freeing node 0x19b7c20
or similar
BONUS POINTS
If you want to go the verbose route, I'd suggest the sanest way is to have the base-template parameterized on the Node type, not the list-element (because partial specializations don't go with function templates).
Here's something that also works:
Live On Coliru
template <typename Node, typename = typename Node::is_my_list_impl_nodetype> void intrusive_ptr_add_ref(Node const*) noexcept;
template <typename Node, typename = typename Node::is_my_list_impl_nodetype> void intrusive_ptr_release(Node const*) noexcept;
template<typename T> class list {
class node {
using is_my_list_impl_nodetype = std::true_type;
std::size_t mutable refcount_;
// friends of list because accessing private nested class node
friend void intrusive_ptr_add_ref<node, std::true_type>(node const* p) noexcept;
friend void intrusive_ptr_release<node, std::true_type>(node const* p) noexcept;
};
boost::intrusive_ptr<node> node_{new node};
};
template<typename Node, typename>
void intrusive_ptr_add_ref(Node const* p) noexcept {
p->refcount_ += 1;
}
template<typename Node, typename>
void intrusive_ptr_release(Node const* p) noexcept {
if (--p->refcount_)
return;
std::cout << "freeing node " << static_cast<void const*>(p) << "\n";
}
The whole SFINAE on is_my_list_impl_nodetype is to prevent an open template from creating ambiguous overloads if you have more intrusive pointer usages in your translation unit that use other addref/release methods.
I am writing a generalized container using a class template, with a restriction (policy) that the items stored in the container should derive from a specific base class.
Here is the definition of the class template
// GenericContainer.hpp
// --------------------------------------
class ContainerItem
{
protected:
virtual ContainerItem& getInvalid() = 0;
public:
virtual ~ContainerItem();
bool isValid() const;
};
template<typename D, typename B>
class IsDerivedFrom
{
static void Constraints(D* p)
{
B* pb = p; // this line only works if 'D' inherits 'B'
pb = p; // suppress warnings about unused variables
}
protected:
void IsDerivedFrom2() { void(*p)(D*) = Constraints; }
};
// Force it to fail in the case where B is void
template<typename D>
class IsDerivedFrom<D, void>
{
void IsDerivedFrom2() { char* p = (int*)0; /* error */ }
};
template <class T>
class GenericContainer : public IsDerivedFrom<T, ContainerItem>
{
private:
typedef std::vector<T> TypeVect;
void addElement(const T& elem);
TypeVect m_elems;
public:
unsigned int size() const;
T& elementAt(const unsigned int pos);
const T& elementAt(const unsigned int pos) const;
};
template <class T>
void GenericContainer<T>::addElement(const T& elem)
{
m_elems.push_back(elem);
}
template <class T>
unsigned int GenericContainer<T>::size() const
{
return m_elems.size();
}
template <class T>
T& GenericContainer<T>::elementAt(const unsigned int pos)
{
unsigned int maxpos = m_elems.size();
if (pos < maxpos)
return m_elems[pos];
return T::getInvalid();
}
template <class T>
const T& GenericContainer<T>::elementAt(const unsigned int pos) const
{
unsigned int maxpos = m_elems.size();
if (pos < maxpos)
return m_elems[pos];
return T::getInvalid();
}
// Class to be contained (PURPOSELY, does not derive from ContainerItem)
// Data.hpp
//----------------------------------------------------------------
class Data
{ /* implem details */};
// Container for Data items
// Dataset.h
// ----------------------------------------------------------------------------
#include "GenericContainer.hpp"
#include "Data.hpp"
class Dataset: public GenericContainer<Data>
{
public:
Data& getInvalid();
};
// C++ source
// -----------------------------------------------------------
#include "Dataset.hpp"
Dataset ds;
Can anyone explain why the code above compiles?.
[Edit]
The code above should NOT compile for two reasons:
The class 'Data' does NOT derive from ContainerItem, and yet it can be stored in GenericContainer (as illustrated by the class Dataset). Incidentally, this issue has now been resolved thanks to the answer given by Omifarious and jdv
The class 'Data' does NOT implement the pure virtual method declared in the ABC ContainerItem - using the fixes recommended in the answers below, the first issue (enforcement of policy) is resolved, however the compiler fails to notice that Data does not implement the getInvalid() method of the ContainerItem 'interface'. Why is the compiler missing this glaring mistake?
BTW, compiler and OS details are:
g++ (Ubuntu 4.4.3-4ubuntu5) 4.4.3
Change IsDerivedFrom2 to IsDerivedFrom and it fails to compile in just the expected manner.
The problem is that a method from a template class is never instantiated if it isn't called. Changing the name makes it a constructor, so it then ends up being called by the constructors of classes derived from IsDerivedFrom. It will still compile to empty code. The compiler will optimize it away the dead assignment.
I would recommend you not write template code like this yourself if you can manage to use Boost, particularly is_base_of from the Boost type traits library.
In particular, your GenericContainer template can be more simply and easily implemented this way using Boost:
#include <boost/static_assert.hpp>
#include <boost/type_traits/is_base_of.hpp>
template <class T>
class GenericContainer
{
private:
typedef std::vector<T> TypeVect;
void addElement(const T& elem);
TypeVect m_elems;
public:
unsigned int size() const;
T& elementAt(const unsigned int pos);
const T& elementAt(const unsigned int pos) const;
GenericContainer() {
BOOST_STATIC_ASSERT( (::boost::is_base_of<ContainerItem, T>::value) );
}
};
template <class T>
void GenericContainer<T>::addElement(const T& elem)
{
m_elems.push_back(elem);
}
template <class T>
unsigned int GenericContainer<T>::size() const
{
return m_elems.size();
}
template <class T>
T& GenericContainer<T>::elementAt(const unsigned int pos)
{
unsigned int maxpos = m_elems.size();
if (pos < maxpos)
return m_elems[pos];
return T::getInvalid();
}
template <class T>
const T& GenericContainer<T>::elementAt(const unsigned int pos) const
{
unsigned int maxpos = m_elems.size();
if (pos < maxpos)
return m_elems[pos];
return T::getInvalid();
}
The Constraints function is not generated because IsDerivedFrom2 is never referenced. This is required behavior for C++. Maybe it helps to call it from the constructor. Otherwise, check the boost library for functionality like this.