compiler declaration order issue?

Have an error I can't figure out how to work around in Ref_List.h on line 15. Here is the code.

main.cpp
1
2
3
4
5
6
7
8
9
#include "Sync_List.h"

int main()
{
  Sync_List::Src_List<int> source;
  Sync_List::Ref_List<int> reference;

  return 0;
}


Sync_List.h
1
2
3
4
5
6
7
#ifndef SYNC_LIST_H
#define SYNC_LIST_H

#include "Src_List.h"
#include "Ref_List.h"

#endif 


Src_List.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#ifndef SRC_LIST_H
#define SRC_LIST_H

#include <list>
#include "Ref_List.h"

namespace Sync_List
{
template<typename T>
class Src_List
{
  private: template<typename T> friend class Ref_List;

           typedef std::list<typename Ref_List<T>::iterator> Link_List;
	   struct Data
	   {
	     T data;
	     Link_List link;
	   };
	   typedef std::list<Data> Data_List;
 
	   Data_List list_;

  public:  typedef typename Data_List::iterator iterator;
};
}
#endif


Ref_List.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#ifndef REF_LIST_H
#define REF_LIST_H

#include <list>
#include "Src_List.h"

namespace Sync_List
{
template<typename T>
class Ref_List
{
  private: template<typename T> friend class Src_List;
		   
	   //Error C2039: 'iterator' : is not member of 'Sync_List::Src::List<T>'...
	   typedef std::list<typename Src_List<T>::iterator> Link_List;
	   typedef T* Data;
	   typedef std::list<Data> Data_List;

	   Data_List list_;
	   Link_List link_;
  
  public:  typedef typename Data_List::iterator iterator;
};
}
#endif
You need indirection in the name to use forward declarations. So I don't think you can do that declaration in the way.
in Src_List.h you #include "Ref_List.h" and in Ref_List.h you #include "Src_List.h" . That's just impossible. You need to reconsider your design
You could do something similiar for Src_List.h, I only did it for Ref, but if you did you would decouple the dependencies by hiding the implementations... also known as "pimpl"

Ref_List.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
#ifndef REF_LIST_H
#define REF_LIST_H

namespace Sync_List
{

	template<typename T> 
	class Src_List;

	template <typename T>
	struct ListPtr;

template<typename T>
class Ref_List
{
  private: 
	  typedef T* Data;
	  typedef std::list<Data> Data_List;

	  Data_List * list_;
	  ListPtr<T> * link_;

  public:  
	  typedef typename Data_List::iterator iterator;
};

#include "Src_List.h"
#include <list>
template <typename T>
struct ListPtr
{
	typedef std::list<typename Src_List<T>::IterType> Link_List;
	Link_List Link;
};
}
#endif 
I went through and reworked my code. Here is the solution I came up with.

Sync_List.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include <list>

template<typename T>
class Sync_List
{
  public:  class Src_List;
           class Ref_List;

  private: struct Ref_Data { T* data; };
           struct Src_Data { T data; typename Ref_List::Link_List link; };
           
           Sync_List(); //can't create Sync_List object
};

#include "Src_List.h"
#include "Ref_List.h" 


Src_List.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include "Sync_List.h"

template<typename T>
class Sync_List<T>::Src_List
{
  private: typedef std::list<Src_Data> Data_List;
  public:  typedef typename Data_List::iterator iterator;
           typedef typename Data_List::const_iterator const_iterator;
  private: typedef std::list<typename Ref_List::const_iterator> Link_List;

           Data_List list_;

  public:  template<typename T> friend class Ref_List;
           template<typename T> friend class Sync_List;

           friend std::ostream& operator<< (std::ostream& _os, const typename Sync_List<T>::Src_List& _rhs)
           {
             if(_rhs.list_.empty()) { return _os << "(empty)|"; }
             Sync_List<T>::Src_List::const_iterator it;
             for(it = _rhs.list_.begin(); it != _rhs.list_.end(); ++it)
               _os << it->data << "|";
             return _os;
           }
};


Ref_List.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#include "Sync_List.h"

template<typename T>
class Sync_List<T>::Ref_List
{
  private: typedef std::list<Ref_Data> Data_List;
  public:  typedef typename Data_List::iterator iterator;
           typedef typename Data_List::const_iterator const_iterator;
  private: typedef std::list<typename Src_List::const_iterator> Link_List;
	       
           Data_List list_;
           Link_List link_;

  public:  template<typename T> friend class Src_List;
           template<typename T> friend class Sync_List;

           friend std::ostream& operator<< (std::ostream& _os, const typename Sync_List<T>::Ref_List& _rhs)
           {
             if(_rhs.list_.empty()) { return _os << "(empty)|"; }
             Sync_List<T>::Ref_List::const_iterator it;
             for(it = _rhs.list_.begin(); it != _rhs.list_.end(); ++it)
               _os << *it->data << "|";
             return _os;
           }
};


Any way I can pull the operator<< definition out of the class?
Any way I can pull the operator<< definition out of the class?

Yes.

What are you trying to accomplish, is Ref and Src supposed to be derived from Sync? This is a lot different than your first approach so now I'm in a tuggarwar with what to suggest. Maybe clarify what you are needing and I can point you in the right direction.

Maybe this will help you.

http://www.cplusplus.com/forum/articles/32021/
Last edited on
Ref and Src are not supposed to be derived from sync.

I was trying to get around an issue where Ref and Src rely on each other to be defined already by pulling some of the structs and typedefs out of Ref and Src and wrapping it in Sync to be "pre-defined" before Src and Ref used them.

Sorry, guess I should have taken the time to explain in a little more detail what I'm trying to accomplish.

I'm trying to create two kinds of lists that can be syncronized together.
I would like them to be wrapped in a templated Sync_List class.
Sync_List object cannot actually be created(private ctor).

Src_List - The Source List contains a list of struct Data:
1
2
3
4
5
6
7
8
9
10
11
class Src_List
{
  struct Data //element
  {
    T data;
    std::list<Ref_List::iterator> link;
  };
  std::list<Data> list_;
  
  typedef std::list<Data>::iterator iterator; //Src_List::iterator
};

A Src_List's data is always inserted at the end, maintaining a new-to-old order.
The user should never be able to sort Src_List.

Ref_List - The Reference List contains a list of T* and a second list of Src_List::iterators.
1
2
3
4
5
6
7
class Ref_List
{
  std::list<T*> list_;
  std::list<Src_List::iterator> tracker_;

  typedef std::list<T*>::iterator iterator //Ref_List::iterator
};

A Ref_List's data can only point to T in a Src_List.
Ref_List can be sorted in any order the user wants.

Ref_List methods
1
2
3
Ref_List::sync(Src_List _src);   //syncs the Ref_List with the Src_List
Ref_List::sync()                 //syncs all Src_Lists the Ref_List has been previously synced with
Ref_List::desync(Src_List _src); //desyncs Ref_List from Src_List, removes all data pointers 


Iterators
When a Src_list and Ref_List are synced together, they must be able to track some information about each other. This is where the iterators come in.

std::list<Ref_List::iterator> link
When a Src_List element is deleted, every Ref_List::T* that points to that element must also be deleted. A list of Ref_List::iterators paired with a Src_List::T is used to accomplish this.(struct Ref_List::Data)

std::list<Src_List::iterator> tracker
When a Ref_List::sync() call is made, the Ref_List must keep track of the last Src_List element since the last call to Ref_List::sync(). This is done with a Src_List::iterator.

Issue
Ref_List relies on Src_List::iterator being defined
Src_List relies on Ref_List::iterator being defined
Need to find a way to work around this. Currently looking over the solution from my previous post. Ran into some iterator issues but might just be a syntax thing. Still looking for suggestions.

Goal
Ability to use Sync_Lists like this:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#include "Sync_List.h"

int main
{
  Sync_List<int>::Src_List src_list;
  Sync_List<int>::Ref_List ref_list;

  src_list.push_back(25);   //add to src
  src_list.push_back(342);  //add to src
  src_list.push_back(-79);  //add to src
  std::cout << "src_list: |" << src_list << std::endl;
  std::cout << "ref_list: |" << ref_list << std::endl;
  std::endl;

  ref_list.sync(src_list);  //sync ref with src
  std::cout << "src_list: |" << src_list << std::endl;
  std::cout << "ref_list: |" << ref_list << std::endl;
  std::endl;

  src_list.remove(342);     //remove from src(and ref)
  src_list.push_back(222);  //add to src(ref not syncd)
  std::cout << "src_list: |" << src_list << std::endl;
  std::cout << "ref_list: |" << ref_list << std::endl;
  std::endl;

  ref_list.sync();          //sync ref
  std::cout << "src_list: |" << src_list << std::endl;
  std::cout << "ref_list: |" << ref_list << std::endl;

  return 0;
}


output:

src_list: |25|342|-79|
ref_list: |empty|

src_list: |25|342|-79|
ref_list: |25|342|-79|

src_list: |25|-79|222|
ref_list: |25|-79|

src_list: |25|-79|222|
ref_list: |25|-79|222|
I was trying to get around an issue where Ref and Src rely on each other to be defined already by pulling some of the structs and typedefs out of Ref and Src and wrapping it in Sync to be "pre-defined" before Src and Ref used them.


Do they truly rely on each other in such a way that they need to be defined? Meaning could you have done...

1
2
3
4
5
6
7
8
9
10
11
12
template<typename T>
class Src; //forward declare

template<typename T>
class Ref{
   //declarations using Src references and pointers
};

#include "Src.h" //See how this is done after the declaration?
//now implementations
template<typename T>
Ref<T>::SomeFunc(){//...} 


This could be done in both classes. Now if that doesn't clear up the cyclic dependencies then you could go one step further and create an implementation class. What do I mean?

1
2
3
4
5
#include "Src.h"
class SrcImpl{
   Src * pSrcList; //Or whatever it is could have been reference or object
   Src srcList; //See?
}


Now inside Ref.h
1
2
3
4
5
class SrcImpl;
class Ref
{
    SrcImpl * pimpl; //Just a pointer to the implementation of what you actually wanted.
}
Last edited on
Topic archived. No new replies allowed.