how to properly include .h, and .tpp - c++

I have the following project structure:
This a handler for the "IOPin" class:
//IOPinHandler class
//IOPinHandler.h
#include <type_traits>
class IOPin; //forward declaration required
class IOPinHandler
{
public:
explicit IOPinHandler() { }
virtual ~IOPinHandler() { }
void checkBool(const bool& b);
void checkInt(const int& b);
template<typename T>
void modifyIOPinMember(IOPin& ioPin, const T& param);
};
//To avoid multiple definitions
#ifndef _OD_
void IOPinHandler::checkBool(const bool& b)
{
//Do stuff
}
void IOPinHandler::checkInt(const int& b)
{
//Do stuff
}
#endif
The following is the .tpp file for the definition of modifyIOPinMember member.
//IOPinHandler class
//IOPinHandler.tpp
template<typename T>
void IOPinHandler::modifyIOPinMember(IOPin& ioPin, const T& param)
{
if constexpr(std::is_same_v<T, int>)
{
checkInt(param);
ioPin.m2 = param;
}
else if constexpr(std::is_same_v<T, bool>)
{
checkBool(param);
ioPin.m1 = param;
}
}
The following is the "IOPin" class, the one meant to be handled by the class above. Since IOPinHandler's modifyIOPinMember member requires to know the definition of "IOPin" (its complete type) then, the IOPinHandler.tpp file is included in IOPin.h file as follows:
//IOPin class
//IOPin.h
//To avoid multiple definitions
#define _OD_
#include "IOPinHandler.h"
class IOPin
{
public:
explicit IOPin(const bool& b, const int& n):m1(b), m2(n) { _handler = new IOPinHandler; }
void setInt(const int& n) { _handler->modifyIOPinMember(*this, n); }
void setBool(const bool& b) { _handler->modifyIOPinMember(*this, b); }
private:
bool m1{false};
int m2{0};
IOPinHandler* _handler{nullptr};
friend class IOPinHandler;
};
#include "IOPinHandler.tpp"
The problem is that calling either setInt or SetBool methods, result in a compile time error:
//main.cpp
#include "IOPin.h"
IOPin a(false, 0);
int main()
{
a.setInt(89);
a.setBool(true);
return 0;
}
This is the error:
/usr/bin/ld: /tmp/ccpKv7HW.o: in function `void IOPinHandler::modifyIOPinMember<int>(IOPin&, int const&)':
main.cpp:(.text._ZN12IOPinHandler17modifyIOPinMemberIiEEvR5IOPinRKT_[_ZN12IOPinHandler17modifyIOPinMemberIiEEvR5IOPinRKT_]+0x27): undefined reference to `IOPinHandler::checkInt(int const&)'
/usr/bin/ld: /tmp/ccpKv7HW.o: in function `void IOPinHandler::modifyIOPinMember<bool>(IOPin&, bool const&)':
main.cpp:(.text._ZN12IOPinHandler17modifyIOPinMemberIbEEvR5IOPinRKT_[_ZN12IOPinHandler17modifyIOPinMemberIbEEvR5IOPinRKT_]+0x27): undefined reference to `IOPinHandler::checkBool(bool const&)'
collect2: error: ld returned 1 exit status
What am I missing over here?
I know that a solution is to create a "IOPinHandler.cpp" file and put there the definitions for "checkBool" and "checkInt" methods, however I dont want to have a separate .cpp file only for that.
Thanks in advance.

In C++, we almost never include the implementation file, only header (.h) files; and, if your class is templated, all class's function implementations should be in header only; no secondary file is needed or advised, and you should always use header guards for your header files, used as follows:
#ifndef ANY_UNIQUE_NAME // recommended related to header file name
#define ANY_UNIQUE_NAME
//#includes <...>
//header code
#endif
Then you include headers when you need them.

Related

Why is my c++ singleton not working on Clion?

I want to have a singleton in my project but some errors occur
this is my codes in three separate files.:
//---------------My main.cpp code
#include <iostream>
#include "Sports/BBVB.h"
int main() {
bbvb;
return 0;
}
// ---------------------------my BBVB.h code
#ifndef SAMAVAR_BBVB_H
#define SAMAVAR_BBVB_H
typedef struct VBResult{
int set1=-1;
int set2=-1;
int set3=-1;
int set4=-1;
int set5=-1;
}VBResult;
#include "Sport.h"
#include "../TournamentStuf/Tournament.h"
class BBVB: public Sport {
protected:
vector<Tournament<VBResult>> tours;
public:
static BBVB& getInstance(){
static BBVB b;
return b;
}
private:
BBVB(){}
public:
BBVB(BBVB const&)=delete;
void operator=(BBVB const&) = delete;
//-------------Setter------------
//------------Getter-------------
vector<Tournament<VBResult>> getTours() const;
Tournament<VBResult> getTourById(int id) const;
//----------Others---------------
void addTour(Tournament<VBResult> v);
};
BBVB &bbvb=BBVB::getInstance();
#endif //SAMAVAR_BBVB_H
//------------------my Store and restore code
#ifndef SAMAVAR_STOREANDRESTORE_H
#define SAMAVAR_STOREANDRESTORE_H
#include "../Sports/BBVB.h"
#include "../Sports/PingPong.h"
#include "../Sports/Wrestling.h"
void Start(BBVB &b);
void Update(const BBVB &b);
void Start(PingPong &p);
void Update(const PingPong &p);
void Start(Wrestling &w);
void Update(const Wrestling &w);
#endif //SAMAVAR_STOREANDRESTORE_H
I have a bbvb instance of BBVB but it says you have multiple definitions of it.
I'm new to Clion and I don't have enough information about somethings like cmake and I feel the problem is because of it.
I want to have something like cout and cin in iostream.so by including my BBVB I can access this object.
Clion shows error below:
CMakeFiles\Samavar.dir/objects.a(BBVB.cpp.obj):BBVB.cpp:(.bss+0x0): multiple definition of `bbvb'
CMakeFiles\Samavar.dir/objects.a(main.cpp.obj):main.cpp:(.bss+0x0): first defined here
CMakeFiles\Samavar.dir/objects.a(StoreAndRestore.cpp.obj):StoreAndRestore.cpp:(.bss+0x0): multiple definition of `bbvb'
CMakeFiles\Samavar.dir/objects.a(main.cpp.obj):Samavar-master/Sports/BBVB.h:24: first defined here
collect2.exe: error: ld returned 1 exit status

linker complains about multiple definition even there are inclusion guards

I can't figure out why the code does not compile, even when I have the include guards to prevent repetitive compilation
The main class foo.h:
#ifndef FOO_H_INCLUDED
#define FOO_H_INCLUDED
#include <iostream>
class Foo;
template<int TDim>
struct Foo_Helper
{
static bool Compare(const Foo& this_foo, const Foo& other_foo);
};
class Foo
{
public:
Foo(const int& Value) : mValue(Value) {}
virtual ~Foo() {}
const int& Value() const {return mValue;}
template<int TDim>
bool Compare(const Foo& rother_foo) {return Foo_Helper<TDim>::Compare(*this, rother_foo);}
private:
int mValue;
};
#endif
#include "foo.hpp"
foo.hpp to define the template specialization:
#ifndef FOO_HPP_INCLUDED
#define FOO_HPP_INCLUDED
template<>
bool Foo_Helper<1>::Compare(const Foo& this_foo, const Foo& other_foo)
{
return this_foo.Value() == other_foo.Value();
}
template<>
bool Foo_Helper<2>::Compare(const Foo& this_foo, const Foo& other_foo)
{
return this_foo.Value() == other_foo.Value();
}
#endif
The two source files:
src1.cpp:
#include "foo.h"
class Test1
{
public:
bool test()
{
Foo f1(1);
Foo f2(2);
return f1.Compare<1>(f2);
}
};
src2.cpp:
#include "foo.h"
class Test2
{
public:
bool test()
{
Foo f1(1);
Foo f2(2);
return f1.Compare<2>(f2);
}
};
CMakeLists.txt:
set(file_list
src1.cpp
src2.cpp
)
add_library(Test SHARED ${file_list})
The error messsage:
Linking CXX shared library libTest.so
CMakeFiles/Test.dir/src2.cpp.o: In function `Foo_Helper<1>::Compare(Foo const&, Foo const&)':
/home/hbui/workspace/c++/multiple_definition_error/foo.hpp:7: multiple definition of `Foo_Helper<1>::Compare(Foo const&, Foo const&)'
CMakeFiles/Test.dir/src1.cpp.o:/home/hbui/workspace/c++/multiple_definition_error/foo.hpp:7: first defined here
CMakeFiles/Test.dir/src2.cpp.o: In function `Foo_Helper<2>::Compare(Foo const&, Foo const&)':
/home/hbui/workspace/c++/multiple_definition_error/foo.hpp:13: multiple definition of `Foo_Helper<2>::Compare(Foo const&, Foo const&)'
CMakeFiles/Test.dir/src1.cpp.o:/home/hbui/workspace/c++/multiple_definition_error/foo.hpp:13: first defined here
collect2: error: ld returned 1 exit status
make[2]: *** [multiple_definition_error/libTest.so] Error 1
make[1]: *** [multiple_definition_error/CMakeFiles/Test.dir/all] Error 2
make: *** [all] Error 2
I thought the inclusion guard has prevented the two functions in foo.hpp to be compiled. However, it looks like that each cpp file compile its own functions. In this case, how to properly define the template specialized functions?
The header guards stop the header being included twice in the same translation unit. Your problem is that the definitions of the Compare specializations will be defined in two translation units, but are not marked inline. This means that when the linker tries to link the object files produced by test1.cpp and test2.cpp, it gives you a multiple definition error. If you mark the specializations as inline then they can be defined in two TUs and the linker will just throw away one of the definitions:
template<>
inline bool Foo_Helper<1>::Compare(const Foo& this_foo, const Foo& other_foo)
//^^^^
{
return this_foo.Value() == other_foo.Value();
}
template<>
inline bool Foo_Helper<2>::Compare(const Foo& this_foo, const Foo& other_foo)
//^^^^
{
return this_foo.Value() == other_foo.Value();
}
You can also put specialization code in .cpp. I think it may be the best solution since specialization (usually) is closely related to the newly created classes (Test1 and Test2).
Alternatively put
template<>
bool Foo_Helper<1>::Compare(const Foo& this_foo, const Foo& other_foo)
{
return this_foo.Value() == other_foo.Value();
}
template<>
bool Foo_Helper<2>::Compare(const Foo& this_foo, const Foo& other_foo)
{
return this_foo.Value() == other_foo.Value();
}
into foo.cpp (instead of foo.hpp) and in foo.hpp only say that specialization is "extern".
Additionally you should move class declarations from src1.cpp to src1.hpp ;)

C++ class template undefined reference to function [duplicate]

This question already has answers here:
undefined reference to template function [duplicate]
(2 answers)
Closed 6 years ago.
I keep getting undefined reference when i call the two functions from my template class "add" and "greater" in my main function.
So, i have:
number.h
#ifndef NUMBER_H
#define NUMBER_H
template <class T>
class number {
public:
T x;
T y;
number (int a, int b){
x=a; y=b;}
int add (T&);
T greater ();
};
#endif
number.cpp
#include "number.h"
template <class T>
int number<T>::add (T& rezAdd){
rezAdd = x+y;
return 1;
}
template <class T>
T number<T>::greater (){
return x>y? x : y;
}
And my main file is: resolver.cpp
#include <stdio.h>
#include <stdlib.h>
#include "number.h"
int main (int argc, char **argv) {
int aux;
number<int> c(3,5);
c.add(aux);
printf ("number added [%d]\n", c.add(aux));
printf ("greater number: [%d]\n", c.greater());
return 0;
}
The errors that i keep getting are:
g++ -Wall -o tema1 resolver.cpp number.cpp
/tmp/ccX483J4.o: In function `main':
resolver.cpp:(.text+0x34): undefined reference to `number<int>::add(int&)'
resolver.cpp:(.text+0x47): undefined reference to `number<int>::add(int&)'
resolver.cpp:(.text+0x64): undefined reference to `number<int>::greater()'
collect2: ld returned 1 exit status
make: *** [all] Error 1
Thanks for the help in advance!
I prefer to have all of my functions in the .cpp file, regardless of whether they are template functions or regular functions. And there is a way to do that with some basic #ifndef magic. Here's what you can do:
main.cpp
#include "myclass.hpp"
int main()
{
// ...
}
myclass.hpp
#ifndef MYCLASS
#define MYCLASS
template<class T>
class MyClass
{
T val;
public:
MyClass(T val_);
}
#define MYCLASS_FUNCTIONS
#include "myclass.cpp"
#endif
myclass.cpp
#ifndef MYCLASS_FUNCTIONS
#include "myclass.hpp"
// regular functions:
// ...
#else
// template functions:
template<class T>
MyClass<T>::MyClass(T val_)
:val(val_)
{}
// ...
#endif
Here's how the precompiler sees it. We have two .cpp files.
When we compile main.cpp we:
include myclass.hpp
check that MYCLASS is undefined, and it is
define it
give compiler the definitions of the generated class (from template class)
include myclass.cpp
define MYCLASS_FUNCTIONS
check if MYCLASS_FUNCTIONS is defined, it is
give compiler the definitions of the generated functions (from template functions)
When we compile myclass.cpp
check if MYCLASS_FUNCTIONS is defined, it isn't
include myclass.hpp
check that MYCLASS is undefined, and it is
define it
give compiler the definitions of the class
include myclass.cpp
include myclass.hpp again
this time MYCLASS is defined so do nothing inside, return to myclass.cpp
check if MYCLASS_FUNCTIONS is defined, it is
give compiler the definition of the generated functions (from template functions)
exit include twice
pass to the compiler all the regular functions
Your class is named wrong. Your class is named cai where all your functions belong to a class named number: http://ideone.com/ZayX0c
One more thing.. you cannot have templates in the .cpp file. Template functions/defintions go in the header along with the class declaration. This is the reason for your undefined function error. Non-template functions go in the .cpp.
#include <cstdio>
#include <cstdlib>
template <class T>
class number {
public:
T x;
T y;
number (int a, int b){
x=a; y=b;}
int add (T&);
T greater ();
};
template <class T>
int number<T>::add (T& rezAdd){
rezAdd = x+y;
return 1;
}
template <class T>
T number<T>::greater (){
return x>y? x : y;
}
int main (int argc, char **argv) {
int aux;
number<int> c(3,5);
c.add(aux);
printf ("number added [%d]\n", c.add(aux));
printf ("greater number: [%d]\n", c.greater());
return 0;
}
Move the definitions of the add and greater function templates into your number.h.
Remember that add and greater aren't functions, they're function templates. To create actual functions, the compiler has to instantiate the template for specific types, such as int, and it can only do that if it has access to the template's definition at the point where it discovers that an instance is needed.
When you compile number.cpp, the compiler has access to the templates' definitions, but it doesn't see any code that requires a specific instance (such as number<int>), so it doesn't generate instances.
When you compile resolver.cpp, the compiler sees that it needs to instantiate those templates for the int type, but it can't since it doesn't have their definitions. So it generates "external references", basically notes telling the linker to look for those functions in some other object file.
The result is that the function templates don't get instantiated in either object file — in one because the compiler didn't know that it should, and in the other because it couldn't — so when the linker goes looking for them (to resolve those external references), it can't find them. That's why you get the error.
Moving the template function definitions into the header makes them visible to the compiler while it's compiling main.cpp, so it's able to instantiate those functions for the int type. Function templates typically need to be defined in header files, rather than .cpp files, for exactly this reason.

failing to invoke template class, c++

I've defined a template class like so (providing .hpp file):
#ifndef PERSOANLVEC_H_
#define PERSOANLVEC_H_
#include <vector>
using namespace std;
template<class T, class PrnT> class PersoanlVec {
public:
PersoanlVec();
~PersoanlVec();
void push_back(T t);
void erase(int index);
PersoanlVec& operator[](int index);
const PersoanlVec& operator[](int index) const;
void print() const;
size_t size();
private:
vector<T> _vector;
};
#endif /* PERSOANLVEC_H_ */
Now, everything compiles ok with this class. When I try to use it I get
undefined reference to PersoanlVec<Person, Person>::PersoanlVec()'.
Here's where I call it:
#include "Person.h"
#include "PersoanlVec.hpp"
#include <cstdlib>
int main(void)
{
Person p1("yotam");
Person p2("yaara");
PersoanlVec<Person,Person> *a = new PersoanlVec<Person,Person>(); //<---ERROR HERE
return EXIT_SUCCESS;
}
This is my first try with templates, its not very clear for me obviously. I DO have a constructor with no parameters, Any ideas?
Thanks!
Do you have the content of your constructor and functions in a .cpp file? If yes, there's your problem. Put them in the header file, possible just inline in the class itself:
template<class T, class PrnT> class PersoanlVec {
public:
PersoanlVec(){
// code here...
}
~PersoanlVec(){
// code here...
}
void push_back(T t){
// code here...
}
void erase(int index){
// code here...
}
PersoanlVec& operator[](int index){
// code here...
}
const PersoanlVec& operator[](int index) const{
// code here...
}
void print() const{
// code here...
}
size_t size(){
// code here...
}
private:
vector<T> _vector;
};
For the reason, have a look here.
I am pretty sure you just forgot to add the file to the compilation process. Be careful with your misspelling, since that can cause generic pain.
Whenever you have different compilation units (classes for example, each with their .h/.cpp), your classes need to know of the interfaces, reason for which you normally include the header files, yet the compiler also needs to know the implementations so that it can bind together your binary file.
As such, you will need to call the compiler passing all the .cpp files in your project to it, otherwise it will fail letting you know you are referencing unimplemented pieces.
You need to have all of your template function definitions held in the header file rather than the CPP file - this is basically because the template definition will be used multiple times to create multiple types depending on what parameters you pass in to it as type parameters around your code. The only template related functions that should ever be defined in the CPP file are template specialization functions - those where you want to explicitly say (if user passed in type A and B then do this specifically instead of the default action).

Understanding template classes in c++ - problem with new-operator

Dear all, I've been stuck with this problem now for a few days and my searches were not successful.
What I am trying to do:
I want a template reader class (VariableReader) to handle different types of variables (usually unsigned int and pointers to vector).
I started with
#ifndef READER_H_
#define READER_H_
#include <string>
namespace BAT {
template <typename variableType = unsigned int>
class VariableReader {
public:
VariableReader<variableType>();
VariableReader<variableType>(std::string varName);
virtual ~VariableReader<variableType>();
std::string getVariableName();
void setVariableName(std::string varName);
bool isValidVariableName(std::string varName);
variableType getVariable();
private:
std::string variableName;
variableType variable;
};
}
#endif
and
#include "../../interface/Readers/VariableReader.h"
namespace BAT {
template<typename variableType>
VariableReader<variableType>::VariableReader() :
variableName("") {
// TODO Auto-generated constructor stub
}
template <typename variableType>
VariableReader<variableType>::VariableReader(std::string varName) :
variableName(varName) {
}
template <typename variableType>
std::string VariableReader<variableType>::getVariableName() {
return variableName;
}
template <typename variableType>
void VariableReader<variableType>::setVariableName(std::string varName) {
if (VariableReader::isValidVariableName(varName)) {
variableName = varName;
}
}
template <typename variableType>
bool VariableReader<variableType>::isValidVariableName(std::string varName) {
return varName != "";
}
template <typename variableType>
VariableReader<variableType>::~VariableReader() {
// TODO Auto-generated destructor stub
}
}
However, although it seems to compile I can't use it within other projects.
EDIT: forgot to post test-code:
#include "cute.h"
#include "ide_listener.h"
#include "cute_runner.h"
#include "Readers/VariableReader.h"
using namespace BAT;
static VariableReader<int> *reader;
void setUp(){
reader = new VariableReader<int>::VariableReader();//this is problem-line
}
void thisIsATest() {
ASSERTM("start writing tests", false);
}
void runSuite(){
cute::suite s;
//TODO add your test here
s.push_back(CUTE(thisIsATest));
cute::ide_listener lis;
cute::makeRunner(lis)(s, "The Suite");
}
int main(){
runSuite();
}
I get following error message:
Building target: BAT_Tests
Invoking: GCC C++ Linker
g++ -L"/workspace/BAT/Debug Gcov" -fprofile-arcs -ftest-coverage -std=c99 -o"BAT_Tests" ./src/Test.o -lBAT
./src/Test.o: In function `setUp()':
/workspace/BAT_Tests/Debug Gcov/../src/Test.cpp:13: undefined reference to `BAT::VariableReader<int>::VariableReader()'
collect2: ld returned 1 exit status
make: *** [BAT_Tests] Error 1
As I understand it the linker tries to find the constructor for VariableReader, which is not explicitly defined since I want to have a general constructor only.
Please help me to understand what I am missing.
The C++ FAQ Lite section on How can I avoid linker errors with my template functions? shows two solutions:
Move the template class's methods into the .h file (or a file included by the .h file).
Instantiate the template in the .cpp file using template VariableReader<unsigned int>;.
The constructor(s) and destructor doesn't need the template arguments in it. In addition, template classes must have the full source available to compile- you can't declare the members and define them in another translation unit like you can with normal classes.