how to adjust a c++ code to work with template class - c++

Following codes are part of a Red Black Tree program which has to take item as a char or int, so I decided to use a template class, however I don't know how to extend it through the complete program and the compiler sends me thousand errors:
The code has German names, so if it makes it easier to understand, I will translate some of them:
baum = tree
knote = node
links = left
rechts = right
rot = red
doppel = double
mittlere = middle
eltern = parent
einfuegen = insert
rs = rb = red black
Knote.hpp
#pragma once
template <class T>
class Knote {
public:
Knote(T data = 0);
bool rot;
T item;
Knote *links;
Knote *rechts;
Knote *eltern;
};
Knote.cpp
#include "Knote.hpp"
Knote<int>::Knote(int data)
{
this->item = data;
eltern = nullptr;
links = nullptr;
rechts = nullptr;
rot = true;
}
now how should I do it for the rest?
Baum.hpp
#pragma once
#include "Knote.hpp"
#include <vector>
class Baum
{
public:
Baum();
void einfuegen(int x);
void ausgabe_levelorder();
void ausgabe_inorder();
private:
Knote<int>* head;
void rs_einfuegen(Knote<int>* &knote, Knote<int>* &eltern, int x, bool sw);
int rot(Knote<int>* &knote);
void links_rotation(Knote<int> * &links_knote);
void rechts_rotation(Knote<int> * &links_knote);
void levelorder(Knote<int>* knote, std::vector<Knote<int>*> &knoteQueue, int niveau, std::vector<int> &niveauQueue);
void sort_levelorder(std::vector<Knote<int>*> &knoteQueue, std::vector<int> &niveauQueue);
void inorder(Knote<int>* knote);
};
Baum.cpp
#include "Baum.hpp"
#include <iostream>
using namespace std;
Baum::Baum()
{
...
}
// XXX
void Baum::einfuegen(int x)
{
...
}
// XXX
int Baum::rot(Knote<int>* &knote)
{
...
}
// XXX
void Baum::rs_einfuegen(Knote<int> *& knote, Knote<int> *&eltern, int x, bool sw)
{
...
}
// XXX
void Baum::links_rotation(Knote<int>* &links_knote)
{
...
}
// XXX
void Baum::rechts_rotation(Knote<int>* &rechts_knote)
{
...
}
// XXX
void Baum::ausgabe_levelorder()
{
...
}
// XXX
void Baum::levelorder(Knote<int>* knote, vector<Knote<int>*> &knoteQueue, int niveau, vector<int> &niveauQueue)
{
...
}
// XXX
void Baum::sort_levelorder(vector<Knote<int>*> &knoteQueue, vector<int> &niveauQueue)
{
...
}
// XXX
void Baum::ausgabe_inorder()
{
inorder(head->rechts);
cout << endl;
}
// XXX
void Baum::inorder(Knote<int>* knote)
{
if (knote != nullptr)
{
inorder(knote->links);
cout << knote->item << " ";
inorder(knote->rechts);
}
}

Don't need to use Knote<T> in the class. Just use Knote. Instead of
Knote<T> *links;
Knote<T> *rechts;
Knote<T> *eltern;
just use:
Knote *links;
Knote *rechts;
Knote *eltern;
When you use the class template, make sure you provide a template parameter.
Knote* head;
is not right. You need to use
Knote<int>* head;
or
Knote<char>* head;
You pick the type that is appropriate for Baum.
Move the implementation of Knote to the .h file from the .cpp file. See Why can templates only be implemented in the header file?.

For Knote.h, your template <typename T> line should be template <class T>
Also, in your constructor for Knote, you can't assign an int (data) to a T variable (item). For the constructor, you should have T data, instead of int data, since you don't know what type data needs to be (because it's a template).
Templated classes also don't have a cpp file. The implementation has to go in the .h after the class declaration (unless forward declared). If you do want to separate your header and "implementation" code parts, keep the .h as normal, but make an .hpp file for your method implementations. In the .h after the class declaration, put #include "Knote.hpp".
For normal methods, the format goes like the following:
template <typename T>
void Knote<T>::myMethod(parameters)
{
//normal method stuff
}
For friend methods that take the templated class as a parameter, such as an overloaded the insertion operator (<<), the format goes like this:
//in class declaration in .h
template <class T>
class Bob
{
//variables here
template <typename U>
void myfunc(Bob<U> value); //have to use a different template variable
}
//define as normal in the .hpp (or further down the file if no .hpp used)

Related

How can I get rid of the <error-type> type that is appearing in my method template? Both the input to the method and the class are templates

I am getting the error
declaration is incompatible with "void spectrogram<T>::update(<error-type> x)
I don't see any difference between the declaration and the definition of the method, not sure why it is complaining about just this one definition and not the constructor or destructor.
Here is vComplex.hpp
#ifndef VCOMPLEX_H
#define VCOMPLEX_H
template <class T>
class vComplex {
public:
T* realp;
T* imagp;
int length; // for bookkeeping
vComplex(void) { }
vComplex (T* I, T* Q, int len) {
realp = I;
imagp = Q;
length = len;
}
~vComplex(void) {
free(realp);
free(imagp);
}
void put(T* I, T*Q, int len) {
realp = I;
imagp = Q;
length = len;
}
};
#endif
the function declaration for update in spectrogram.hpp, with other members removed:
#ifndef SPECTROGRAM_H
#define SPECTROGRAM_H
template <typename T>
class spectrogram {
public:
void update(vComplex<T> x);
};
#endif
and the function signature (and includes) for update in spectrogram.cpp:
#include <stdio.h>
#include <math.h>
#include "spectrogram.hpp"
#include "vComplex.hpp"
template <typename T>
void spectrogram<T>::update(vComplex<T> x) {
//do stuff
}
In VS 2017, I get the red underline under update and everything inside of it breaks basically. VS is saying T is undefined which I'm assuming is caused by the overall error. I have to use dynamically allocated pointers, I don't have the option of using other types or containers.

Moving a generic template with restrictions out of the class definition

The following example compiles and shows the correct endresult. EDIT: in the sense that three lines are printed.
#include <iostream>
using namespace std;
struct normal
{
static void log(const char * out) { cout << out << endl; }
};
struct other
{
static void log(const char * out) { cout << out << endl; }
};
//Implementation inside the class declaration
template<typename output = normal>
class LogUser_H
{
public:
void print() { output::log("template"); }
};
//Move Implementation moved out of the class declaration
template<typename output = normal>
class LogUser_CPP
{
public:
void print();
};
//Specialised definitions
void LogUser_CPP<struct normal>::print(void) { normal::log("normal specialisation"); }
void LogUser_CPP<struct other>::print(void) { other::log("other specialisation"); }
//Template definition ?
//void LogUser_CPP</*??*/output/*??*/>::print(void)
//{
// output::log("template");
//}
int main()
{
LogUser_H<> H;
H.print();
LogUser_CPP<> C1;
C1.print();
LogUser_CPP<other> C2;
C2.print();
}
The class LogUser_H has a method that calls a function in a struct. LogUser_CPP is meant to do the same with the twist that I want to move the method definition out of the class definition and write it below. Doing so I no longer have a definition for output and I can not get to the function in structs that fulfil the output requirement. I can however provide specialized versions of struct and compile that way.
How can I delete the two specialized implementations void LogUser_CPP<struct normal>::print(void) and void LogUser_CPP<struct other>::print(void)? In want to replace them with a generic implementation looking something like the commented out implementation void LogUser_CPP</*??*/output/*??*/>::print(void).
EDIT 1:
I tried the following:
//Specialised definitions
//void LogUser_CPP<struct normal>::print(void) { normal::log("normal specialisation"); }
//void LogUser_CPP<struct other>::print(void) { other::log("other specialisation"); }
template<>
void LogUser_CPP<>::print(void)
{
output::log("template");
}
This will not compile.
EDIT 2:
I tried the following:
//Specialised definitions
//void LogUser_CPP<struct normal>::print(void) { normal::log("normal specialisation"); }
//void LogUser_CPP<struct other>::print(void) { other::log("other specialisation"); }
template<typename output>
void LogUser_CPP<>::print(void)
{
output::log("template");
}
This will not compile.
The error is error C3211: 'LogUser_CPP<normal>::print' : explicit specialization is using partial specialization syntax, use template <> instead
Could this be compiler specific? This computer has VS2013 Express on it.
Use:
template <>
void LogUser_CPP<normal>::print(void) { normal::log("normal specialisation"); }
template <>
void LogUser_CPP<other>::print(void) { other::log("other specialisation"); }
or
template<typename output>
void LogUser_CPP<output>::print(void)
{
output::log("template");
}

error: using-declaration for non-member at class scope using std::cout

I downloaded a c++ project and was able to compile it using a makefile generated by cmake.
However when I try to add my own series of .h files in one of the .hh files of the project I start to get a million of errors, one of them being:
error: using-declaration for non-member at class scope
using std::cout;
When the .h file that contains
using std::cout is used elsewhere it works, but when added to this project it gives this error.
What can be the problem?
using std::cout;
using std::endl;
class TextManager : public FileManager {
public:
TextManager (const char * filename);
void scanFile (Image &image, Scene &scene);
void scanObjectModel (Image &image, Scene &scene);
void getImageData (Image &image);
void getMaterialData (Scene &scene);
void getLightData (Scene &scene);
void getSphereData (Scene &scene);
void getPlaneData (Scene &scene);
void getTriangleData (Scene &scene);
int getLineValue (int size);
void getLineValue2 (float (&lineNumbers) [10], Scene &scene, int &lineNumbersIndex);
void getVerticesValues (int initPos, Scene &scene);
private:
std::string line;
float fractionaryTenPowers [6];
};
Problem solved. Was the lack of a bracket to close the declaration of one of the classes that was causing it.
The error means you've done this:
struct Foo {
using std::cout;
...
};
That's not valid C++, in a class body you can only add a using-declaration for members of base classes, not arbitrary names.
You can only add using std::cout at namespace scope or inside a function body.
You can put it in the class as long as you put it under the public or private sections.
#include <iostream>
namespace CoolNamespace
{
struct AnotherReallyLongClassName
{
int a = 75;
};
struct SomeReallyLongClassName
{
int a = 42;
};
} // namespace CoolNamespace
class Widget
{
// You can't do this though!
// using ShorterName = CoolNamespace::SomeReallyLongClassName;
public:
// You can use a using statement inside of a class!
using ShorterName = CoolNamespace::SomeReallyLongClassName;
ShorterName foo;
int get_another_name()
{
return bar.a;
}
private:
// You can do it here also!
using AnotherName = CoolNamespace::AnotherReallyLongClassName;
AnotherName bar;
};
int main()
{
Widget widget;
std::cout << widget.foo.a << std::endl;
// Also, if you can reference public using statements from the class definition.
Widget::ShorterName thing;
std::cout << thing.a << std::endl;
// But you can't do this because it's private.
// Widget::AnotherName name;
return 0;
}
Indeed, check if you have one open bracket in one of the member functions in the class declaration.
I did this in .h file;
class foo{
void cat();
void bar{
void dog();
}
in .cc file I defined the member functions
void foo::cat(){
std::cout<<"This is cat"<<std::endl;
}
void foo::bar(){
std::cout<<"hello"<<std::endl;
}
void foo::dog(){
std::cout<<"meow"<<std::endl;
}
But notice I used { instead of; for member function bar in .h file. That's causing the error. (At least for me).

Linker error : unsolved external symbol [duplicate]

This question already has answers here:
Why can templates only be implemented in the header file?
(17 answers)
Closed 9 years ago.
I'm trying to create a template c++ Stack, and i'm having some issue with the linker.
I've tried to put all the classes into one cpp file, and it works just fine, but the problem begin once I separate them into different files
here's my classes
main class :
#include <iostream>
#include "stack.h"
using namespace std;
int main()
{
Stack<double>* st = new Stack<double>();
st->push(new Data<double>(10));
cout << st->pop()->getData();
return 0;
}
stack.h :
#ifndef STACK_H
#define STACK_H
#include "data.h"
template <class T>
class Stack
{
public:
Stack():_current(NULL){}
void push(Data<T>* const);
Data<T>* pop();
private:
Data<T>* _current;
};
#endif;
stack.cpp :
#include "stack.h"
template <class T>
Data<T>* Stack<T>::pop()
{
if(this->_current == NULL)
{
cout << "Empty stack." <<endl;
return NULL;
}
else
{
Data<T>* tmpPtr = this->_current;
this->_current = this->_current->getPrev();
return tmpPtr;
}
}
template <class T>
void Stack<T>::push(Data<T>* const data)
{
if(this->_current == NULL) // Empty stack;
{
_current = data;
_current->setPrv(NULL);
}
else
{
Data<T>* tmpPtr = this->_current;
this->_current = data;
this->_current->setPrv(tmpPtr);
}
}
data.h
#ifndef DATA_H
#define DATA_H
template <class T>
class Data
{
public:
Data(T data):_data(data){}
T getData() const { return this->_data; }
void setPrv(Data* const prev){ this->_prev = prev; }
Data* getPrev() const { return this->_prev; }
private:
Data<T>* _prev;
T _data;
};
#endif
Put all the definitions of the template class functions in the .h. They basically aren't allowed to be in separate files.
This occurs becauses templates are not like typical classes. The compiler will generate a class for you off of your template instantiation. Because of this, the compiler will need to know where to lookup the function definitions, so put them inside the .h where the class is defined.
Template functions are not compiled until they're specialized(used), and your stack.cpp doesn't produce any machine code. Move them to stack.h

error C2079: 'stackNameSpace::StackNode<T>::value' uses undefined class

the interface of Stack.h
#include "stdafx.h"
//use linkedlist to implement the stack
//which is different from using the array to implement the stack
#ifndef STACK_H
#define STACK_H
using namespace std;
namespace stackNameSpace {
template<class T>
struct StackNode {
T value;
T min_value; //current local min value
StackNode* next;
};
typedef StackNode<class T>* StackNodePtr;
template<class T>
class Stack {
private:
StackNodePtr top;
public:
Stack();
Stack(const Stack& a_stack);
~Stack();
bool empty() const;
T pop();
void push(T the_value);
T getMin();
};
} //end of namespace
#endif
The implementation of the stack.h
#include "stdafx.h"
//use linkedlist to implement the stack
//which is different from using the array to implement the stack
#ifndef STACK_CPP
#define STACK_CPP
#include <iostream>
#include <cstdlib>
#include "Stack.h"
using namespace std;
namespace stackNameSpace {
template<class T>
Stack<T>::Stack() : top(NULL) //here should be Stack<T> instead of Stack
{}
template<class T>
Stack<T>::Stack(const Stack& a_stack) {
if (a_stack.top == NULL) {
return NULL;
}
else {
StackNodePtr currentOld = a_stack.top;
//construct the top of the new stack
StackNodePtr currentNew = new StackNode<class T>;//the struct
currentNew->value = currentOld->value;
currentNew->min_value = currentOld->min_value;
top = currentNew;
//contruct the rest node in the stack
currentOld = currentOld->next;
while (currentOld != NULL) {
currentNew->next = new StackNode<class T>;
currentNew = currentNew->next;
currentNew->value = currentOld->value;
currentNew->min_value = currentOld->min_value;
currentOld = currentOld->next;
}
currentOld->next = NULL;
}
}
template<class T>
Stack<T>::~Stack() {
T data;
while (!empty()) {
data = pop();
}
}
template<class T>
bool Stack<T>::empty() const {
return (top == NULL);
}
template<class T>
T Stack<T>::pop() {
if (empty()) {
cout << "Error: popping an empty stack.\n";
exit(1);
}
T result = top->value;
StackNodePtr temp = new StackNode<class T>;
temp = top;
top = top->next;
delete temp;
return result;
}
template<class T>
void push(T the_value) {
StackNodePtr temp = new StackNode<class T>;
temp->value = the_value;
temp->min_value = min(the_value, getMin());//This is Much better
//temp->min_value = top->min_value; //This is NOT secure, since top may be NULL
temp->next = top; //update the top node
top = temp;
}
template<class T>
T getMin() {
if (top == NULL)
return INT_MAX;
else {
return top->min_value;
}
}
} //end of namespace
#endif
The function using the Stack class
#include "stdafx.h"
#include <iostream>
#include "Stack.h" //this is not the <stack>, which is STL
//using namespace std; //NOTE: this must be wrong! because can not use multiple namespace at the same time
using namespace stackNameSpace;
using std::cout;
using std::endl;
int main() {
Stack<int> sWithMin;
sWithMin.push(5);
cout<< sWithMin.getMin() << endl;
sWithMin.push(4);
cout<< sWithMin.getMin() << endl;
sWithMin.push(5);
cout<< sWithMin.getMin() << endl;
sWithMin.push(3);
cout<< sWithMin.getMin() << endl;
sWithMin.push(6);
cout<< sWithMin.getMin() << endl;
return 0;
}
When I compile the project, I get an error in main() that "error C2079: 'stackNameSpace::StackNode::value' uses undefined class 'stackNameSpace::T'"
I can not figure out the reason why it has the error. Could anyone please help me?
namespace stackNameSpace {
template<class T>
struct StackNode {
T value;
T min_value; //current local min value
StackNode* next;
};
So StackNode is a template that depends on a type parameter T.
typedef StackNode<class T>* StackNodePtr;
This is not part of a template definition and class T refers to a class named T.
(Actually class T always refers to a class named T, except in the construct template <class T>, which could be replaced by template <typename T>. With a template definition with type parameter T that type must be referred to using plain T, not class T.)
As you haven't declared a class named T yet, the StackNodePtr definition implicitly declares an incomplete class type at surrounding namespace scope (i.e the incomplete class type is ::stackNameSpace::T).
template<class T>
class Stack {
private:
StackNodePtr top;
Now here StackNodePtr is not dependent on the template parameter T. Instead it is a pointer to a fixed type StackNode<::stackNameSpace::T> and top->value will be of incomplete type class T unrelated to the template parameter of Stack.
If you use a Stack<int> and instantiate anything using top->value within such a stack, you'll see the error you show.
BTW: another, unrelated issue is that definitions of templates (including member functions of class templates) must be visible at the point where a template is instantiated. Typically that means that you should not put template member definition into a cppfile which is compiled separately. Instead they should be in a header file that is included wherever the template is used.
While JoergB correctly pointed out the issue with the code that you posted, I would like to throw some light on what he was explaining in the last part of his answer.
When using templates in Visual studio I would make sure that the header and implementation of the class come under a single compilation unit. Try renaming Stack.cpp to Stack.inl and include it at the end of Stack.h
void push(T the_value);
T getMin();
};
} //end of namespace
#include "Stack.inl"
#endif
Be sure to exclude Stack.inl from build. Right click on it in the Solution Explorer > Properties > Exclude from build > Yes.