0

I'm going insane over this issue and I can't find out what's going on. I've been away from C++ programming for a couple of years and apparently I'm missing something. I currently have the following files:

Node.h

#ifndef LIGHTHOUSE_NODE_H
#define LIGHTHOUSE_NODE_H

#include <iostream>
#include "Problem.cpp"

using namespace std;

template <class ActionType, class StateType>
class Node {
    private:
        Node<ActionType, StateType>* parent;
        ActionType* action;
        StateType* state;
        unsigned int cost;

    public:
        Node(Node<ActionType, StateType>* parent, ActionType* action, StateType* state, unsigned int cost);
        Node();
        ~Node();

        Node* makeNode( Node<ActionType, StateType>* parent, ActionType* action, Problem<ActionType, StateType> problem );

        Node* getParent();
        ActionType* getAction();
        StateType* getState();
        unsigned int getCost();

        bool operator == (Node<ActionType, StateType> tbCompared);
        virtual string toString();
};
#endif

Node.cpp:

/**
* Declaration of non virtual methods within Node class, I don't think this is what gives problems
**/

Problem.h

#ifndef LIGHTHOUSE_PROBLEM_H
#define LIGHTHOUSE_PROBLEM_H

#include "Node.h"

template<class ActionType, class StateType>
class Problem {
private:
    StateType* initialState;

public:
    Problem();
    explicit Problem( StateType* initialState );
    ~Problem();

    StateType* getInitialState();
    void setInitialState( StateType* initialState );

    virtual ActionType** actions( StateType* state );
    virtual StateType* result( ActionType* action, StateType* state );
    virtual bool goalTest( StateType* state );
    virtual unsigned int cost( ActionType* action, StateType* state );
};
#endif

Problem.cpp

#include "Problem.h"

template<class ActionType, class StateType>
Problem<ActionType, StateType>::Problem(StateType *initialState) {
    this->initialState = initialState;
}

template<class ActionType, class StateType>
Problem<ActionType, StateType>::Problem() {
    this(nullptr);
}

template<class ActionType, class StateType>
Problem<ActionType, StateType>::~Problem() {
    delete initialState;
}

template<class ActionType, class StateType>
StateType *Problem<ActionType, StateType>::getInitialState() {
    return this->initialState;
}

template<class ActionType, class StateType>
void Problem<ActionType, StateType>::setInitialState(StateType *initialState) {
    this->initialState = initialState;
}

For completeness' sake I include the errors log I get.

**Error log: **

FAILED: CMakeFiles/Lighthouse.dir/GenericProblem/Problem.cpp.obj 
C:\PROGRA~1\JETBRA~1\CLION2~1.1\bin\mingw\bin\G__~1.EXE   -g -std=gnu++20 -MD -MT CMakeFiles/Lighthouse.dir/GenericProblem/Problem.cpp.obj -MF CMakeFiles\Lighthouse.dir\GenericProblem\Problem.cpp.obj.d -o CMakeFiles/Lighthouse.dir/GenericProblem/Problem.cpp.obj -c C:/Users/nicco/CLionProjects/Lighthouse/GenericProblem/Problem.cpp
In file included from C:/Users/nicco/CLionProjects/Lighthouse/GenericProblem/Node.h:6,
                 from C:/Users/nicco/CLionProjects/Lighthouse/GenericProblem/Problem.h:5,
                 from C:/Users/nicco/CLionProjects/Lighthouse/GenericProblem/Problem.cpp:1:
C:/Users/nicco/CLionProjects/Lighthouse/GenericProblem/Problem.cpp:4:1: error: 'Problem' does not name a type
    4 | Problem<ActionType, StateType>::Problem(StateType *initialState) {
      | ^~~~~~~
C:/Users/nicco/CLionProjects/Lighthouse/GenericProblem/Problem.cpp:9:1: error: 'Problem' does not name a type
    9 | Problem<ActionType, StateType>::Problem() {
      | ^~~~~~~
C:/Users/nicco/CLionProjects/Lighthouse/GenericProblem/Problem.cpp:14:1: error: 'Problem' does not name a type
   14 | Problem<ActionType, StateType>::~Problem() {
      | ^~~~~~~
C:/Users/nicco/CLionProjects/Lighthouse/GenericProblem/Problem.cpp:19:19: error: expected initializer before '<' token
   19 | StateType *Problem<ActionType, StateType>::getInitialState() {
      |                   ^
C:/Users/nicco/CLionProjects/Lighthouse/GenericProblem/Problem.cpp:24:13: error: expected initializer before '<' token
   24 | void Problem<ActionType, StateType>::setInitialState(StateType *initialState) {
      |             ^
In file included from C:/Users/nicco/CLionProjects/Lighthouse/GenericProblem/Problem.h:5,
                 from C:/Users/nicco/CLionProjects/Lighthouse/GenericProblem/Problem.cpp:1:
C:/Users/nicco/CLionProjects/Lighthouse/GenericProblem/Node.h:23:86: error: 'Problem' has not been declared
   23 |             Node* makeNode( Node<ActionType, StateType>* parent, ActionType* action, Problem<ActionType, StateType> problem );
      |                                                                                      ^~~~~~~
C:/Users/nicco/CLionProjects/Lighthouse/GenericProblem/Node.h:23:93: error: expected ',' or '...' before '<' token
   23 |             Node* makeNode( Node<ActionType, StateType>* parent, ActionType* action, Problem<ActionType, StateType> problem );
      |                                                                                             ^
[3/4] Building CXX object CMakeFiles/Lighthouse.dir/GenericProblem/Node.cpp.obj
ninja: build stopped: subcommand failed.

I can't get my head around the reason why Problem would be considered undefined?

Ken White
  • 123,280
  • 14
  • 225
  • 444
Baffo rasta
  • 320
  • 1
  • 4
  • 17
  • 2
    After solving your current problem you will encounter this error: [Why can templates only be implemented in the header file?](https://stackoverflow.com/questions/495021/why-can-templates-only-be-implemented-in-the-header-file) – Yksisarvinen Apr 04 '22 at 20:40
  • 1
    You should never `#include` a `.cpp` file. – 0x5453 Apr 04 '22 at 20:42
  • 2
    `#include "Problem.cpp"` ... in a header no less, ugh. Anyway, Node.h includes Problem.cpp which includes Problem.h which includes Node.h. Basically you have circular inclusion. – WhozCraig Apr 04 '22 at 20:42
  • all that code in the problem.cpp file needs to be in the .hpp file,. All template code goes in .h(pp) files – pm100 Apr 04 '22 at 20:44
  • @0x5453: Thanks for the heads up, I fixed it. The problem is still there anyway. – Baffo rasta Apr 04 '22 at 20:44
  • Did you remove offending `include` altogether or replace it with `#include "Node.hpp"`? Because the latter will still create circular include and still produce the same error. – Yksisarvinen Apr 04 '22 at 20:45
  • @Yksisarvinen: I replaced it with `#include "Node.h"`. The circular dependency is bound to be in the nature of the context I'm trying to model, I just don't know how to make it feasible in C++ – Baffo rasta Apr 04 '22 at 20:47
  • 2
    What were the last few lines of code added, when the compilation error started happening? Surely this huge pile of code wasn't written all at once, and only then an attempt was made to compile it? That always ends in tears. Experienced C++ developers never write a novel, and only then try to see if it works. They write just a few lines at a time, compile, run and test the results, then write the next few lines of code. This way all development problems are small, simple, and easy to fix. – Sam Varshavchik Apr 04 '22 at 20:49
  • @WhozCraig: Yeah you're right, removing the `include` of `Node.h` fixed the problem. – Baffo rasta Apr 04 '22 at 20:52
  • `using namespace std;` is another one, especially ***in a header file*** [that always creates more problems than it fixes](https://stackoverflow.com/questions/1452721/). – Sam Varshavchik Apr 04 '22 at 20:53
  • @SamVarshavchik: I actually wrote the whole novel before trying to compile. At the end of the day the classes I wrote are mainly interfaces and didn't expect it to go this bad. Indeed there was just this single issue, which I now fixed as of the above comment, and the remaining part was apparently correct. – Baffo rasta Apr 04 '22 at 20:54
  • @SamVarshavchik: Yep I eventually removed it since I only used it for `std::string` – Baffo rasta Apr 04 '22 at 20:55
  • I can see the need for `Problem<>` to be known by `Node.h`. I cannot see the need for `Node<>` to be known by `Problem.h` so this is certainly salvageable, especially if you move your implementations where they belong (the headers). – WhozCraig Apr 04 '22 at 20:55
  • 1
    Nobody expects an avalanche of compilation errors, any more than they expect the Spanish Inquisition. But, both are inevitable, and are only a matter of time. – Sam Varshavchik Apr 04 '22 at 20:56
  • Unrelated, `this(nullptr)` Um... w.t.f ??? :-P – WhozCraig Apr 04 '22 at 20:57
  • @WhozCraidef: If no initial state is specified it's supposed to be null, is it the wrong way to express this? `this(nullptr)` is just a differen way of doing this... – Baffo rasta Apr 04 '22 at 21:01
  • `this(nullptr)` makes no sense whatsoever, in *any* context. [It shouldn't even compile](https://godbolt.org/z/s46Mncx1j). – WhozCraig Apr 04 '22 at 22:27
  • `this(nullptr)` is invoking the following constructor: `explicit Problem( StateType* initialState )` with `nullptr` parameter, I think you missed that :P – Baffo rasta Apr 04 '22 at 22:48

0 Answers0