0
votes

I have a project for university that I managed to get working using my own makefile/terminal command. BUT I get zero marks on the university's auto marker. I THINK this is because they use a makefile that tries to execute all three cpp files in one line with the compiler(if that's even possible), it's difficult to tell, because the marker doesn't give any feedback. When I try to compile all three .cpp files(g++ main.cpp A.cpp B.cpp) I get the following error messages:

  • B.cpp:4:3: error: redefinition of ‘T B::getVal()’ T B::getVal(){
  • A.cpp:4:6: error: redefinition of ‘void A::print(B)’ void A::print(B bInstance){

In my MRE the following needs to stay true:

  • A and B must have a .h and .cpp file
  • main.cpp may only include "A.h"
  • A must require B for it to work

Here is my MRE: -It makes an instance of B and then uses an instance of A to print a message with the value of instance B.

main.cpp

#include "A.h"

int main(){
  B<char> b1;
  b1.val='B';
  A<char> a1;
  a1.print(b1);
}

A.h

#ifndef AAAA
#define AAAA

#include<iostream>
#include "B.h"

using namespace std;

template <class T>
class A{
public:
  void print(B<T> bInstance);
};

#include "A.cpp"

#endif

A.cpp

#include "A.h"

template <class T>
void A<T>::print(B<T> bInstance){
  cout<<"I am A, and I am using "<<bInstance.getVal()<<endl;
}

B.h

#ifndef BBBB
#define BBBB

template <class T>
class B{
public:
  T val;
  T getVal();
};

#include "B.cpp"

#endif

B.cpp

#include "B.h"

template <class T>
T B<T>::getVal(){
  return val;
}

Working compile and run commands

g++ main.cpp

./a.out

Commands it should work with(if possible)

g++ main.cpp A.cpp B.cpp

./a.out
2
I'm still new here and I've realized I use too many words to describe my problems. I tried to cut it down, but if this is still too much let me know. - Foxly
Don't include cpp files. - Jarod42

2 Answers

0
votes

You should never #include ".cpp" in headers. Implementations of function templates must be in headers, not in cpp. In your example, A.cpp and B.cpp are not needed at all. If they are still required by the task, make them empty except for #include directive.

Edit: If your automarker does not like it, you can also try inlining your implementations, e.g.

template <class T>
class B{
public:
  T val;
  T getVal(){
     return val;
  }
};
0
votes

Your problem, with the files as they are right now, is that when you try to compile B.cpp, then this:

#include "B.h"

template <class T>
T B<T>::getVal(){
  return val;
}

and this:

#ifndef BBBB
#define BBBB

template <class T>
class B{
public:
  T val;
  T getVal();
};

#include "B.cpp"

#endif

combines into this:

#ifndef BBBB
#define BBBB

template <class T>
class B{
public:
  T val;
  T getVal();
};

#ifndef BBBB     // <- BBBB has been defined at this point, so everything between  this and the #endif is skipped
#endif

template <class T>
T B<T>::getVal(){
  return val;
}

#endif

template <class T>
T B<T>::getVal(){
  return val;
}

At this point I hope that it is obvious why you are getting the error: B.cpp:4:3: error: redefinition of ‘T B::getVal()’ T B::getVal(){.

The correct fix is to just put the entire template implementation in the header, and get rid of the .cpp file. But if that is not an option because of a messed up automarker, then try to add include-guards to the .cpp file. But be aware that this is bad practice all around (.cpp files should never be #include'ed, and should thus never need include-guards), so if any human sees your code then be prepared for a lot of questions and raised eyebrows.

BUT! The first step should probably be to try and talk to whoever gave you the task because something is wrong here; either with the automarker or with your understanding of how it works. A template class should not have a .cpp file (or it should be empty).