How to properly use Templates? - c++

I am trying to create a vector class that looks something like this:
template <typename T>
class Vector
{
.
.
.
};
#include "vector.cpp"
However, when I start writing my functions in "vector.cpp", CLion complains that I have duplicate functions. How do I work around this? I believe in NetBeans, I can add vector.h & vector.cpp to a folder called "Important Files" which would fix the problem. I am not sure what the equivalent in CLion is.

General Design of a template
example.h
#ifndef EXAMPLE_H
#define EXAMPLE_H
// Needed includes if any
// Prototypes or Class Declarations if any
template<class T> // or template<typename T>
class Example {
private:
T item_;
public:
explicit Example( T item );
~Example();
T getItem() const;
};
#include "Example.inl"
#endif // EXAMPLE_H
Example.inl
// Class Constructors & Member Function implementations
template<class T>
Example<T>::Example( T item ) : item_(item) {
}
template<class T>
Example<T>::~Example() {
}
template<class T>
T Example<T>::getItem() const {
return item_;
}
Example.cpp
#include "Example.h"
// Only need to have the include here unless if
// the class is non template or stand alone functions
// are non-template type. Then they would go here.

Related

Use a derived class type as parameter of a base method in C++

I have the following classes in the following files:
// Tensor.hh
template <class T>
class Tensor {
/* declarations */
}
// Tensor.cpp
#include "Tensor.hh"
// Implementation of Tensor.hh
// Kernel.hh
#include "Tensor.hh"
template <class T>
class Kernel : public Tensor<T> {
/* declarations */
}
// Kernel.cpp
#include "Kernel.hh"
// Implementation of Kernel.hh
Is it possible to use a pointer to "Kernel" as parameter of a "Tensor" method?
Something like:
template <class T>
void Tensor<T>::foo(Kernel<T>* kernel) {
// Do something...
}
Yes it is possible. In your Tensor.cpp you will have to include #include "Kernel.hh", and in your Tensor.hh you will have to add a forward declaration:
template<typename>
class Kernel;
Usually I would really avoid forward declaring template classes, and I would avoid circular dependencies. Sometimes they are not avoidable, but sometimes yes.
Another solution would be to simply implement foo as a free function in another header:
void foo(Tensor<T>& tensor, Kernel<T>* kernel) {
// ...
}
That way you break the circular dependency, and you get bonus encapsulation.
I think you need to use forward declaration of the class Kernel. I could compile following:
template <class T>
class Kernel;
template <class T>
class Tensor {
/* declarations */
void foo(Kernel<T>* kernel);
};
template <class T>
class Kernel: public Tensor<T> {
};
The implementation of your class templates needs to be visible to your users. So it's best to put the implementation directly in the header file.
// Forward declare Kernel<T> so Tensor<T> can know about it for foo()
template<typename T>
class Kernel;
// Define Tensor<T>
template<typename T>
class Tensor {
void foo(Kernel<T>* kernel);
...
};
// Define Kernel<T>
template<typename T>
class Kernel : public Tensor<T> {
...
};
// Define Tensor<T>::foo here since Kernel<T> needs to be defined
// for it to do anything meaningful with it
template<typename T>
void Tensor<T>::foo(Kernel<T> *kernel) {
// Do something...
}

C++ template: <class> does not name a type

Newbie to C++ so please forgive me. I'm trying to write a simple template class to implement the Stack data structure functionality. I've read through this question to understand how template declaration and implementation works: Why can templates only be implemented in the header file?. But I would like to use the solution where class declaration and implementation are separate (not defined inline in .h).
MyStack.h:
#include "StackNode.h"
#include "MyStack.tpp"
template <typename T>
class MyStack
{
private:
StackNode<T> *top;
public:
MyStack();
virtual ~MyStack();
};
MyStack.tpp:
#include "MyStack.h"
template <typename T>
MyStack<T>::MyStack()
: top(nullptr)
{
}
template <typename T>
MyStack<T>::~MyStack()
{
}
main.cpp:
#include "MyStack.h"
int main() {
MyStack<int> myStack;
return 0;
}
However compiling the above gives this error:
../src/MyStack.tpp:11:1: error: 'MyStack' does not name a type
../src/MyStack.tpp:18:1: error: 'MyStack' does not name a type
I know I'm missing something, but don't understand what. Thanks!
The problem is that you are including the .tpp file, which contains the class method definitions, before the class has actually been declared yet. You need to move that #include statement below the class declaration instead.
Also, the .tpp file should not be #include'ing the .h file that originally #include'd it. In fact, that won't work correctly since your .h file is missing header guards to prevent multiple inclusions within the same translation unit (ie, main.cpp in this case). So, you would end up with MyStack.h which includes MyStack.tpp which includes MyStack.h again, which causes an error when it tries to re-declare things that are already declared. Always declare a header guard in your .h files.
Try this instead:
MyStack.h:
#ifndef MyStack_H
#define MyStack_H
#include "StackNode.h"
template <typename T>
class MyStack
{
private:
StackNode<T> *top;
public:
MyStack();
virtual ~MyStack();
};
#include "MyStack.tpp"
#endif
MyStack.tpp:
template <typename T>
MyStack<T>::MyStack()
: top(nullptr)
{
}
template <typename T>
MyStack<T>::~MyStack()
{
}

Templated friend class in nontemplate class, where friend also uses the class

Background
I have a non templated class, called library and a templated class library_file, which is intended to have a template parameter F for different file types (like std::fstream or QFile and so on) to save/load a library on.
Assumption
So I put a forward declaration of library_file before my definition of library and a friend declaration in the last one. Because, since library_file includes library I would otherwise be in a dependency circle.
Problem
The friend declaration fails with
In file included from /Users/markus/Entwicklung/cmake_Spielwiese/library.cpp:4:
/Users/markus/Entwicklung/cmake_Spielwiese/library.h:12:12: error: C++ requires a type specifier for all declarations
friend library_file;
~~~~~~ ^
/Users/markus/Entwicklung/cmake_Spielwiese/library.h:12:12: error: friends can only be classes or functions
2 errors generated.
Code
/*! #file library.h
* */
#ifndef CMAKE_CPP_SPIELWIESE_LIBRARY_H
#define CMAKE_CPP_SPIELWIESE_LIBRARY_H
template <typename F>
class library_file;
class library {
template <typename F>
friend library_file;
};
#endif //CMAKE_CPP_SPIELWIESE_LIBRARY_H
/*! #file library_file.h
* */
#ifndef CMAKE_CPP_SPIELWIESE_LIBRARY_FILE_H
#define CMAKE_CPP_SPIELWIESE_LIBRARY_FILE_H
#include "library.h"
template <typename F>
class library_file {
F file;
library l;
};
#endif //CMAKE_CPP_SPIELWIESE_LIBRARY_FILE_H
/*! #file main.cpp
* */
#include <fstream>
#include "library.h"
#include "library_file.h"
int main() {
library_file<std::fstream> f;
return 0;
}
/*! #file library.cpp
* */
#include "library.h"
The correct declaration of a template friend class is :
template<class F> friend class library_file;
see Class template with template class friend, what's really going on here?
You forgot the class keyword in library_file.h, it compiles just fine after that
#ifndef CMAKE_CPP_SPIELWIESE_LIBRARY_H
#define CMAKE_CPP_SPIELWIESE_LIBRARY_H
template <typename F>
class library_file;
class library {
template <typename F>
friend class library_file;
};
#endif //CMAKE_CPP_SPIELWIESE_LIBRARY_H

How to separate definition and declaration of child template class

If I have a template class defined as:
#ifndef A_HPP
#define A_HPP
template<class T>
class A
{
public:
int doSomething(int in, bool useFirst);
private:
template<int CNT>
class B
{
public:
int doSomething(int in);
};
B<2> first;
B<3> second;
};
#include "a_imp.hpp"
#endif
Now I can go about having a declaration for A::doSomething in an implementation header file like this
#ifndef A_IMP_HPP
#define A_IMP_HPP
template<class T>
int A<T>::doSomething(int in, bool useFirst)
{
if (useFirst)
return first.doSomething(in);
return second.doSomething(in);
}
#endif
However I do not know how I go about making the declaration for the child class's method. Is it even possible or do I have to do one of the other two ways I can think of doing this, namely defining the methods in the main header or declare the class outside of A.
Please note that I am using C++11 so if this is only doable in that it will still work for me, though a C++98 solution would be good for other people.
You can do it in the following way:
template <class T>
template <int CNT>
int A<T>::B<CNT>::doSomething(int in)
{
// do something
}
Not sure if this is what you're asking, but I guess you need something like this:
template<class T>
template<int CNT>
int A<T>::B<CNT>::doSomething(int in)
{
return /*...*/;
}
Note that the template keyword appears twice, first for the template parameters of A, then for the parameters of nested class B.

Cannot successfully friend a templated method in a templated class because of mutual header inclusion

I have a class that wraps logic for matrix management. Meanwhile I have a set of methods specialized in handling some important time spending matrix manipulation operations (like LU factorization and so on).
The class uses the functions defined in that file. That file needs to have access to that class' elements. I need to make those specialized methods friends of the above-mentioned class. This causes me to include one header in each other header.
My problem
The situation I described before is coded here as follows. The first code refers to mat.hpp.
#ifndef MAT_HPP
#define MAT_HPP
#include "operations.hpp"
namespace nsA {
template <typename T>
// Templated class because matrices can be real or complex
class mat {
// Members...
friend template <typename U>
void exec_lu(const mat<U>& in, const mat<U>& out);
// Members...
} /* class end */
}
#endif
#endif
The second file is operations.hpp
#ifndef OPERATIONS_HPP
#define OPERATIONS_HPP
#include "mat.hpp"
namespace nsA {
namespace nsB {
template <typename T>
void exec_lu(const mat<T>& in, const mat<T>& out);
}
}
#endif
The problem is that the compiler starts complaining.
Note
Consider please that if I comment the friend declaration in mat.hpp but leave the inclusions, the compiler tells me that in 'operations.hpp' type mat is not defined!
If also comment the inclusion in mat.hpp and keep friend declaration commented as well, the compiler is ok!
How to work on this?
Thankyou
You can do this by just adding a couple of forward declarations... But you can even do better with a bit more code:
template <typename T> class mat;
template <typename T> void exec_lu( const mat<T>&, const mat<T>& );
template <typename T>
class mat {
friend void exec_lu<T>( const mat<T>&, const mat<T>& );
};
template <typename T>
void exec_lu( const mat<T>& a, const mat<T>& b ) { ... }
The main difference between this approach and yours (other than fixing the syntax limitations) is that in this approach a single instantiation of exec_lu is granted access to mat<T>, in particular the instantiation that needs access to it. In your code (after fixing), all specializations of exec_lu would have access to any specialization of mat (i.e. exec_lu<int> could access mat<int> private members, but also mat<double>...) and you probably don't want that.
For a longer description of the different options to declare friends of a template, read this answer to a related question.
To get this to work, you need to forward declare the class. It looks like this:
The file mat.hpp:
#ifndef MAT_HPP
#define MAT_HPP
namespace nsA {
template <typename T>
class mat;
namespace nsB {
template <typename T>
void exec_lu(const mat<T>& in, const mat<T>& out);
}
template <typename T>
class mat {
friend void exec_lu(const mat<T>& in, const mat<T>& out);
};
}
#endif
And the file operations.hpp:
#ifndef OPERATIONS_HPP
#define OPERATIONS_HPP
#include "mat.hpp"
namespace nsA { namespace nsB {
template <typename T>
void exec_lu(const mat<T>& in, const mat<T>& out);
}}
#endif
Your original declaration gives out more friendship than mine. Mine only grants friendship to the function that matches the typename of the class.