2

I am trying to create a grid, From what I understand the issue is coming from using a pointer of a template class inside its self which is legal until i try to do stuff with it is when the compiler complains. I am looking for a way to use pointer's to a class of a template inside its self for use in using the pointers and do what I will later. I compile with g++ version 5 the compile command i use is g++ *.cpp -o main -std=c++11 the error i get will follow the snippet for the code.

struct Vector2D 
{
    Vector2D(  ) {  }
    Vector2D( int x , int y ): x( x ) , y( y ) {  } ;

    int x , y ; 

} ;

template <typename A>
class GridNode2D ; 

template <typename T>
class GridNode2D
{
public: 
    GridNode2D(  ) {  } ;
    T data ; 
    Vector2D coOrdinate ; 

    GridNode2D<T>* left, right, up, down ; 

} ;

template <typename T>
class Grid2D
{
public:
    Grid2D(  ) ;

    GridNode2D<T>* head ; 

} ;

template <typename T>
Grid2D<T>::Grid2D(  )
{
    this->head = new GridNode2D<T> ; 
    this->head->right = new GridNode2D<T> ; 

} ;

Errors:

main.cpp: In instantiation of ‘class GridNode2D<bool>’:
<span class="error_line" onclick="ide.gotoLine('main.cpp',39)">main.cpp:39:16</span>:   required from ‘Grid2D<T>::Grid2D() [with T = bool]’
<span class="error_line" onclick="ide.gotoLine('main.cpp',47)">main.cpp:47:18</span>:   required from here
main.cpp:22:26: error: ‘GridNode2D::right’ has incomplete type
     GridNode2D<T>* left, right, up, down ; 
                          ^
main.cpp:15:7: note: definition of ‘class GridNode2D’ is not complete until the closing brace
 class GridNode2D
       ^
main.cpp:22:33: error: ‘GridNode2D::up’ has incomplete type
     GridNode2D<T>* left, right, up, down ; 
                                 ^
main.cpp:15:7: note: definition of ‘class GridNode2D’ is not complete until the closing brace
 class GridNode2D
       ^
main.cpp:22:37: error: ‘GridNode2D::down’ has incomplete type
     GridNode2D<T>* left, right, up, down ; 
                                     ^
main.cpp:15:7: note: definition of ‘class GridNode2D’ is not complete until the closing brace
 class GridNode2D
Some programmer dude
  • 400,186
  • 35
  • 402
  • 621
killer
  • 372
  • 1
  • 5
  • 15

2 Answers2

2

The placement of the asterisk * in the declaration

GridNode2D<T>* left, right, up, down ;

is misleading. The "standard" C way of declaration would make it clearer:

GridNode2D<T> *left, right, up, down ;

In the above it's more clear that the asterisk belongs to the declaration of left, and that's the problem you have: You only declare left as a pointer, not the other variables.

Since the other variables are not pointers, you need the full definition of GridNode2D<T> to be able to define instances of that class, but that's impossible since the objects are part of the GridNode2D<T> itself. Which leads to the errors you get.

Either use the asterisk on all variables in the declaration, or for better readability split the declarations into multiple lines:

GridNode2D<T>* left;
GridNode2D<T>* right;
GridNode2D<T>* up;
GridNode2D<T>* down;
Some programmer dude
  • 400,186
  • 35
  • 402
  • 621
1

The declaration

GridNode2D<T>* left, right, up, down ;

create 1 pointer, and 3 instances. Change it to

GridNode2D<T>* left, *right, *up, *down;

or even

GridNode2D<T>* left = nullptr;
GridNode2D<T>* right = nullptr;
GridNode2D<T>* up = nullptr;
GridNode2D<T>* down = nullptr;
Jarod42
  • 203,559
  • 14
  • 181
  • 302
  • People need to stop teaching to put the asterisk on the left.. this is exactly why it belongs on the right. – Dan Bechard Apr 08 '21 at 07:11
  • 1
    @DanBechard: it is debatable (I would mostly say that pointer belong to the type (you might typedef them)), and it is generally just stylistic concern. problem is mostly one liner multiple declaration (where some mixes is allowed). – Jarod42 Apr 08 '21 at 07:25
  • It belongs to the name, not the type. Even in the case of typedef, it's part of the typedef's name. That's how it has worked since C decls. It's not stylistic.. it's how the type declaration parser works. It is dumb though.. which is why many modern languages have changed it (e.g. Golang). If you're curious about the more complex cases, this covers it quite well (for C, even though it's arguing in favor of Golang): https://blog.golang.org/declaration-syntax – Dan Bechard Apr 08 '21 at 08:36
  • The short explanation is that `int *x;` is read by the parser as "dereferencing the name x gives me a result of type int", *not* "the type of x is a pointer to an int" even though that's how most people describe it when speaking. This matters a lot when you have more complex type decls, but for a simple pointer it's hard to persuade people that right asterisk is technically more correct. – Dan Bechard Apr 08 '21 at 08:41
  • Parser and meaning might mismatch IMO (you might have right recursive rule for addition, whereas it is left associative; token `>>` is now interpreted differently in template declaration). Hard to say that pointer belongs to `intptr` in `using intptr = int*;`. Similarly, I found difficult to associate `*` to unnamed arguments as `void f(int *)`. Parsing indeed explains the logic of the right. Formatters allow to use both styles. I mostly see it as position of `const` (I also prefer the "wrong" order `const int*`). – Jarod42 Apr 08 '21 at 09:15
  • *"dereferencing the name x gives me a result of type int"* But it is not really correct, deferencing x gives `int&`. (You might say that C++ break previous logic though...). How do you read `int &r = x;`? – Jarod42 Apr 08 '21 at 09:18