How to declare a class friend to another before its definition - c++

I have those two classes and I want the edge node to be friend for graph but I don't know how to declare it
The implementation of the graph is based on adjacency lists, I used unique_ptr for the auto deletion.
#ifndef GRAPH_HPP
#define GRAPH_HPP
#include <memory>
using std::unique_ptr;
template<typename Type>
class edgenode {
friend class graph<Type>; //here
public:
edgenode(Type w, int adj);
~edgenode() {};
private:
Type mWeight;
int mAdj;
unique_ptr<edgenode<Type>> mNext;
};
template<typename Type>
edgenode<Type>::edgenode(Type w, int adj)
:mWeight(Type), mAdj(adj) {
mNext = nullptr;
}
///-------------------------------------------------///
template<typename Type>
class graph {
public:
graph(int maxvertices = 1000, bool directed = false);
~graph();
private:
unique_ptr<edgenode<Type>>* mEdges;
int* mDegree;
int mNoOfNodes;
int mNoOfVertices;
int mSize;
bool m_bDirected;
};
template<typename Type>
graph<Type>::graph(int maxvertices = 1000, bool directed = false)
: mSize(maxvertices),
m_bDirected(directed),
mNoOfNodes(0),
mNoOfVertices(0)
{
mDegree = new int[mSize];
mEdges = new unique_ptr<edgenode<Type>>[mSize];
for (int i = 0; i < mSize; ++i) {
mDegree[i] = 0;
mEdges[i] = nullptr;
}
}
template<typename Type>
graph<Type>::~graph() {
delete[] mEdges;
delete[] mDegree;
}
#endif

Forward declare the class template like this:
template<typename Type> class graph;
template<typename Type>
class edgenode {
friend graph<Type>;
// ...

Add template class graph<class T>; before edgenode declaration, it's called a forward declaration:
#include <memory>
using std::unique_ptr;
template class graph<class T>; // this
template<typename Type>
class edgenode {
friend class graph<Type>; //here
public:
...

Related

Implement a template of a Queue, using 2 Classes [duplicate]

This question already has answers here:
Why can templates only be implemented in the header file?
(17 answers)
Closed last year.
I have a problem. I have implemented a Queue, while using a Class "Queue" and a Class "Element".
the problem i have now is, that I can't work out how to create the template for class Element.
If I don't use the template and just use int instead of T. Everything works fine. I already looked for many examples on the Internet. But nobody uses two classes, which is probably more efficient. I think my problem is that i don't know how to use the pointer in templates.
PS: The template in Queue.h and.cpp works i think, but if i start trying to create a template for Element it doesn't work.
My Queue.h file
#ifndef ELEMENT_H
#define ELEMENT_H
#include "Element.h"
template <class T>
class Queue{
public:
explicit Queue(int max_queue);
~Queue() = default;
void enqueue(T inhalt);
Element* dequeue();
Element* show();
bool isEmpty();
private:
Element<T>* front{};
Element<T>* back{};
int max;
int anzahl = 0;
};
#endif
My Queue.cpp file
#include "Queue.h"
#include <iostream>
#include <string>
template <class T>
Queue<T>::Queue(int max_queue){
max = max_queue;
}
template <class T>
void Queue<T>::enqueue(T inhalt){
Element* e = new Element(inhalt);
if(max > anzahl){
if(isEmpty()){
front = back = e;
}else{
back->setNext(e);
back = e;
}
} anzahl++;
}
template <class T>
Element* Queue<T>::dequeue(){
Element* e = front;
front = front->getNext();
e->setNext(nullptr);
return e;
}
template <class T>
bool Queue<T>::isEmpty()
{
return anzahl == 0;
}
template <class T>
Element* Queue<T>::show()
{
return front;
}
My Element.h file
#ifndef QUEUE_H
#define QUEUE_H
class Element{
public:
explicit Element(int);
~Element() = default;
int getInhalt()const;
void setInhalt(int);
Element*getNext()const;
void setNext(Element*);
protected:
int inhalt;
Element* next;
};
#endif
My Element.cpp file
#include <string>
#include "Element.h"
Element::Element( int inhalt_element )
{
inhalt = inhalt_element;
next = nullptr;
}
int Element::getInhalt() const {
return inhalt;
}
void Element::setInhalt(int inhalt) {
Element::inhalt = inhalt;
}
Element* Element::getNext() const {
return next;
}
void Element::setNext(Element *next) {
Element::next = next;
}
The warning I'm getting is main.cpp:(.text+0x1a): undefined reference to `Queue::Queue(int)'
And If I try to use a template for the element class. There are hundreds of lines in the warnings, so I know I'm thinking completely wrong.
I am still pretty novice if it is about programming so any help or any idea would be really appreciated.
Thank you
The implementation of template classes must be done in the .h
The following code compiles.
#include <iostream>
#include <string>
template <class T>
class Element{
public:
Element( T inhalt_element ){
inhalt = inhalt_element;
next = nullptr;
}
T getInhalt() const {
return inhalt;
}
void setInhalt(T inhalt) {
this->inhalt = inhalt;
}
Element<T>* getNext() const {
return next;
}
void setNext(Element<T> *next) {
this->next = next;
}
protected:
T inhalt;
Element<T>* next;
};
template <class T>
class Queue{
public:
Queue(int max_queue){
max = max_queue;
}
void enqueue(T inhalt){
Element<T>* e = new Element<T>(inhalt);
if(max > anzahl){
if(isEmpty()){
front = back = e;
}else{
back->setNext(e);
back = e;
}
} anzahl++;
}
Element<T>* dequeue(){
Element<T>* e = front;
front = front->getNext();
e->setNext(nullptr);
return e;
}
bool isEmpty(){
return anzahl == 0;
}
Element<T>* show(){
return front;
}
private:
Element<T>* front{};
Element<T>* back{};
int max;
int anzahl = 0;
};
int main() {
std::cout << "Hello World!";
Queue<int> queue(10);
return 0;
}

std::variant 'attempting to reference a deleted function'

When trying to compile I get the error: Error C2280 'std::variant<Tree::Position<int>,Tree::Position<std::string>,Tree::Position<double>,Tree::Position<bool>>::variant(const std::variant<Tree::Position<int>,Tree::Position<std::string>,Tree::Position<double>,Tree::Position<bool>> &)': attempting to reference a deleted function
I have a Tree class with a template sub-class Position. When using the load function of the Tree class, an instance of the Position class is added to the Tree's treePositionList. Also in the constructor function of the Position class an instance of the Position class is added to its childenList. I think the problem is related to the adding of an instance to those lists, though I do not understand what goes wrong exactly.
template <typename E>
class Node {
private:
string column;
E element;
public:
Node(E el, string col) { element = el; column = col;}
};
class Tree {
public:
template <typename E>
class Position {
private:
typedef variant<Position<int>, Position<string>, Position<double>, Position<bool>> Position_ManyTypes;
typedef list<Position_ManyTypes> PositionList;
Node<E>* node;
PositionList childrenList;
public:
Position(Tree* tree, const E element, const string column, const Json::Value &children);
Position(Position<E>& position);
~Position();
Position<E>& operator=(const Position<E> &position);
friend class Tree;
};
typedef variant<Position<int>, Position<string>, Position<double>, Position<bool>> Position_ManyTypes;
typedef list<Position_ManyTypes> PositionList;
Tree() {}
bool load(string filename);
private:
PositionList treePositionList;
};
bool Tree::load(string filename) {
ifstream rules_file(filename, ifstream::in);
Json::Value rules;
rules_file >> rules;
rules_file.close();
Position<string> root_position = Position<string>(this, "string123", "string456", rules["children"]);
treePositionList.push_back(root_position);
return true;
}
template <typename E>
Tree::Position<E>::Position(Tree::Position<E>& position) {
node = position.node;
childrenList = position.childrenList;
}
template <typename E>
Tree::Position<E>& Tree::Position<E>::operator=(const Tree::Position<E>& position) {
if (this != &position) {
delete node;
node = position.node;
childrenList = position.childrenList;
}
return *this;
}
template <typename E>
Tree::Position<E>::~Position() {
delete node;
}
template <typename E>
Tree::Position<E>::Position(Tree* tree, const E el, const string col, const Json::Value &children) {
node = new Node<E>(el, col);
Position<string> pos = Position<string>(tree, "string123", "string456", children[0]["children"]);
childrenList.push_back(pos);
}

Compiler error related to public method granting access to private class member

Given the following class template definitions
template<typename T>
class node{
private:
T& data;
shared_ptr<node<T>>& next;
public:
T& get_data(void);
shared_ptr<node<T>>& get_next (void);
public:
node(T&);
~node();
};
template<typename X>
class list{
private:
shared_ptr<X> head;
list(shared_ptr<X>&);
public:
shared_ptr<X>& get_head(void);
void set_head(shared_ptr<X>&);
public:
list();
~list();
public:
int size (void);
};
and the following corresponding method definitions
template<typename T>
shared_ptr<node<T>>& node<T>::get_next(void){
return(this->next);
}
template<typename X>
int list<X>::size (void){
auto h = this->head;
auto count = 0;
while(h){
++count;
h = h->get_next();
}
return count;
}
And the following code in main()
list<node<string>>menu;
auto num_menu_items = menu.size();
the following compiler error ensues:
In instantiation of "int list<X>::size() [with X = node<std::basic_string<char> >]":
error: "std::shared_ptr<node<std::basic_string<char> > >& node<std::basic_string<char> >::next" is private within this context
h = h->get_next();
~~~^~~~
note: declared private here
shared_ptr<node<T>>& next;
Complete source code can be accessed below:
code.hpp
main.cpp
Complete compiler log can be accessed below:
compiler log
Appreciate your thoughts.

Class templates that are both base classes and directly usable

I have two classes representing a graph:
class Node {
public:
void AppendSource(Edge &Edge) { m_Sources.append(&Edge); }
void AppendSink(Edge &Edge) { m_Sinks.append(&Edge); }
QList<Edge *> &Sources() { return m_Sources; }
QList<Edge *> &Sinks() { return m_Sinks; }
QList<Edge *> const &Sources() const { return m_Sources; }
QList<Edge *> const &Sinks() const { return m_Sinks; }
protected:
QList<Edge *> m_Sources;
QList<Edge *> m_Sinks;
}; // Node
class Edge {
public:
Edge(Node &Source, Node &Sink) : m_pSource(&Source), m_pSink(&Sink) {}
Node const &Source() const { return *m_pSource; }
Node const &Sink() const { return *m_pSink; }
Node &Source() { return *m_pSource; }
Node &Sink() { return *m_pSink; }
void SetSource(Node &Source) { m_pSource = &Source; }
void SetSink(Node &Sink) { m_pSink = &Sink; }
protected:
Node *m_pSource;
Node *m_pSink;
}; // Edge
It should be possible to inherit from these classes, in order to add functionality for specific types of graphs. Therefore, the classes should be template classes:
template <class EDGE_TYPE>
class Node {
public:
void AppendSource(EDGE_TYPE &Edge) { m_Sources.append(&Edge); }
void AppendSink(EDGE_TYPE &Edge) { m_Sinks.append(&Edge); }
QList<EDGE_TYPE *> &Sources() { return m_Sources; }
QList<EDGE_TYPE *> &Sinks() { return m_Sinks; }
QList<EDGE_TYPE *> const &Sources() const { return m_Sources; }
QList<EDGE_TYPE *> const &Sinks() const { return m_Sinks; }
protected:
QList<EDGE_TYPE *> m_Sources;
QList<EDGE_TYPE *> m_Sinks;
}; // Node
template <class NODE_TYPE>
class Edge {
public:
Edge(NODE_TYPE &Source, NODE_TYPE &Sink) : m_pSource(&Source), m_pSink(&Sink) {}
NODE_TYPE const &Source() const { return *m_pSource; }
NODE_TYPE const &Sink() const { return *m_pSink; }
NODE_TYPE &Source() { return *m_pSource; }
NODE_TYPE &Sink() { return *m_pSink; }
void SetSource(NODE_TYPE &Source) { m_pSource = &Source; }
void SetSink(NODE_TYPE &Sink) { m_pSink = &Sink; }
protected:
NODE_TYPE *m_pSource;
NODE_TYPE *m_pSink;
}; // Edge
But now it seems no longer possible to use the classes without extending them! A few attempts with the obvious corresponding errors:
new Node(); // 'Node': use of class template requires template argument list
new Node<>(); // 'Node': too few template arguments
new Node<Edge>(); // 'Edge': unspecialized class template can't be used as a template argument for template parameter 'EDGE_TYPE', expected a real type
new Node<Edge<>>(); // 'Edge': too few template arguments
new Node<Edge<Node>>(); // 'Node': unspecialized class template can't be used as a template argument for template parameter 'NODE_TYPE', expected a real type
new Node<Edge<Node<>>>(); // 'Node': too few template arguments
I was hoping to solve this by introducing defaults for the template arguments. A few attempt with their corresponding errors:
template <class EDGE_TYPE = Edge>
class Node { ... }
template <class NODE_TYPE = Node>
class Edge { ... }
new Node<>(); // 'Edge': unspecialized class template can't be used as a template argument for template parameter 'EDGE_TYPE', expected a real type
template <class EDGE_TYPE = Edge<>>
class Node { ... }
template <class NODE_TYPE = Node<>>
class Edge { ... }
new Node<>(); // recursive type or function dependency context too complex
template <class EDGE_TYPE = Edge<Node<EDGE_TYPE>>>
class Node { ... }
template <class NODE_TYPE = Node<Edge<NODE_TYPE>>>
class Edge { ... }
new Node<>(); // 'EDGE_TYPE': undeclared identifier
How can I make Node and Edge both directly usable and extensible though inheritance?
How can I make Node and Edge both directly usable and extensible
though inheritance?
I'll focus on that requirement in bold.
Though you can have the definition of Edge and Node depend on each other, there's no way to make recurring declaration of Edge and Node, because such declaration would yield infinite template recursion:
Node<> = Node<Edge<>> = Node<Edge<Node<>>> = Node<EdgeNode<Edge<>>>> ...
So, if you want Edge<> and Node<> to be directly usable (i.e. instantiateable without making dummy derived classes), then you should break that recursion. For example, by making both Edge and Node depend on some third traits class:
// Forward declaration.
struct DefaultGraphTypes;
template <typename GraphTypes = DefaultGraphTypes>
struct Node;
template <typename GraphTypes = DefaultGraphTypes>
struct Edge;
// Traits class.
template <typename NodeT, typename EdgeT>
struct GraphTypes
{
// Could change this to 'using' in modern C++
typedef NodeT FinalNodeType;
typedef EdgeT FinalEdgeType;
// typedef MayBeSomeOtherParameters ...
};
struct DefaultGraphTypes
: public GraphTypes<Node<DefaultGraphTypes>, Edge<DefaultGraphTypes>>
{
};
// Implementation of graph classes.
template <typename GraphTypes>
struct Node
{
typedef typename GraphTypes::FinalNodeType FinalNodeType;
typedef typename GraphTypes::FinalEdgeType FinalEdgeType;
// ... Your implementation
};
template <typename GraphTypes>
struct Edge
{
typedef typename GraphTypes::FinalNodeType FinalNodeType;
typedef typename GraphTypes::FinalEdgeType FinalEdgeType;
// ... Your implementation
};
// User-derived types.
struct MyNode;
struct MyEdge;
struct MyNode
: public Node<GraphTypes<MyNode, MyEdge>>
{
// Something specific
};
struct MyEdge
: public Edge<GraphTypes<MyNode, MyEdge>>
{
// Something specific
};
// Test
int main()
{
Node<> n1;
Edge<> e1;
MyNode n2;
MyEdge e2;
return 0;
}
IMHO, this can be achieved by inserting forward declarations at the right place. I took parts of OP sample code and completed it to a compilable sample:
#include <iostream>
#include <vector>
#define QList std::vector // Sorry, no Qt at hand in coliru
template <class EDGE_TYPE>
class Node {
public:
void AppendSource(EDGE_TYPE &Edge) { m_Sources.append(&Edge); }
void AppendSink(EDGE_TYPE &Edge) { m_Sinks.append(&Edge); }
QList<EDGE_TYPE *> &Sources() { return m_Sources; }
QList<EDGE_TYPE *> &Sinks() { return m_Sinks; }
QList<EDGE_TYPE *> const &Sources() const { return m_Sources; }
QList<EDGE_TYPE *> const &Sinks() const { return m_Sinks; }
protected:
QList<EDGE_TYPE *> m_Sources;
QList<EDGE_TYPE *> m_Sinks;
}; // Node
template <class NODE_TYPE>
class Edge {
public:
Edge(NODE_TYPE &Source, NODE_TYPE &Sink) : m_pSource(&Source), m_pSink(&Sink) {}
NODE_TYPE const &Source() const { return *m_pSource; }
NODE_TYPE const &Sink() const { return *m_pSink; }
NODE_TYPE &Source() { return *m_pSource; }
NODE_TYPE &Sink() { return *m_pSink; }
void SetSource(NODE_TYPE &Source) { m_pSource = &Source; }
void SetSink(NODE_TYPE &Sink) { m_pSink = &Sink; }
protected:
NODE_TYPE *m_pSource;
NODE_TYPE *m_pSink;
}; // Edge
// forward declarations:
struct WNode;
struct WEdge;
// declaration of derived types
struct WNode: public Node<WEdge>
{
int weight;
};
struct WEdge: public Edge<WNode>
{
int weight;
WEdge(WNode &src, WNode &snk): Edge(src, snk) { }
};
// check whether it compiles
int main()
{
WNode node1, node2;
WEdge edge12(node1, node2);
// done
return 0;
}
Live Demo on coliru
That's the actual trick:
OP carefully used in template class Node and template class Edge only references and pointers to the resp. opposite type. Hence, an incomplete type is fully sufficient to be used as template argument in both cases. These incomplete types are provided by the forward declarations:
// forward declarations:
struct WNode;
struct WEdge;
Afterwards, the classes WNode and WEdge can be derived from Node<WEdge> and Edge<WNode>.
template template parameter might help:
template <typename TEdge>
class Node {
public:
using EDGE_TYPE = TEdge;
void AppendSource(EDGE_TYPE &Edge) { m_Sources.append(&Edge); }
void AppendSink(EDGE_TYPE &Edge) { m_Sinks.append(&Edge); }
QList<EDGE_TYPE *> &Sources() { return m_Sources; }
QList<EDGE_TYPE *> &Sinks() { return m_Sinks; }
QList<EDGE_TYPE *> const &Sources() const { return m_Sources; }
QList<EDGE_TYPE *> const &Sinks() const { return m_Sinks; }
protected:
QList<EDGE_TYPE *> m_Sources;
QList<EDGE_TYPE *> m_Sinks;
}; // Node
template <template <typename> class TNode>
class Edge {
public:
using NODE_TYPE = TNode<Edge>; // which is TNode<Edge<TNode>>
Edge(NODE_TYPE &Source, NODE_TYPE &Sink) : m_pSource(&Source), m_pSink(&Sink) {}
NODE_TYPE const &Source() const { return *m_pSource; }
NODE_TYPE const &Sink() const { return *m_pSink; }
NODE_TYPE &Source() { return *m_pSource; }
NODE_TYPE &Sink() { return *m_pSink; }
void SetSource(NODE_TYPE &Source) { m_pSource = &Source; }
void SetSink(NODE_TYPE &Sink) { m_pSink = &Sink; }
protected:
NODE_TYPE *m_pSource;
NODE_TYPE *m_pSink;
};
Then you might have:
using MyEdge = Edge<Node>;
using MyNode = Node<Edge<Node>>; // Node<MyEdge>
or even:
template <template <typename> class TNode>
class CustomEdge : Edge<TNode> {
// ...
};
using MyNode2 = Node<CustomEdge>;
using MyEdge2 = CustomEdge<Node>;
Demo

custom iterator for a collection interface

I have an interface ICollection implementing a collection ArdalanCollection like this:
template <typename T>
class ICollection
{
public:
virtual void add(T*) = 0;
virtual T* get(int) = 0;
virtual int count() = 0;
};
template <typename T>
class ArdalanCollection :public ICollection<T>
{
public:
ArdalanCollection() {
index = 0;
};
virtual void add(T* obj) {
encapsolateImplementation.insert(make_pair(index++, obj));
};
virtual T* get(int index) {
return encapsolateImplementation[index];
};
virtual int count() {
return encapsolateImplementation.size();
};
private:
int index;
unordered_map < int, T* > encapsolateImplementation;
};
what I want is to have a generic iterator in ICollection interface which can loop all over the internal container elements(I haven't decided to choose unordered_map as my internal container I might change it to boost or something else). I want to use it in this way:
Node *node1 = new Node(1, 0, 0, 0);
Node *node2 = new Node(1, 0, 0, 0);
ICollection<Node> *nodes = new ArdalanCollection<Node>();
nodes->add(node1);
nodes->add(node2);
for (it=nodes->iterator.begin(); it < nodes->iterator.end(); it++) {
}
First your for loop idiom is not correct. It should rather look like
for(auto it = nodes->begin(); it != nodes->end(); it++)
then something along:
template <typename T, typename MyMap>
class ICollection
{
public:
typedef typename MyMap<int, T *>::iterator iterator;
virtual void add(T*) = 0;
virtual T* get(int) = 0;
virtual int count() = 0;
};
should be fine.