friend operators not being found in case of templates

I have the following code:


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
37
38
39
40
41
42
43
44
45
46
template<class Key, class Value>
class BinaryTreeMap
{
private:
	struct Entry
	{
		Key key;
		Value value;

		...
	};
	BinaryTree<Entry> tree;
	friend DataLoader &operator>><Key,Value>(DataLoader &in, BinaryTreeMap<Key, Value> &tree);
	friend DataSaver &operator<<<Key,Value>(DataSaver &out, const BinaryTreeMap<Key, Value> &tree);
	friend DataLoader &operator>><Key,Value>(DataLoader &in, Entry &entry);
	friend DataSaver &operator<<<Key,Value>(DataSaver &out, const Entry &entry);
public:
...
}

template<class Key, class Value>
DataLoader &operator>>(DataLoader &in, BinaryTreeMap<Key, Value> &tree)
{
	return in>>tree.tree;
}

template<class Key, class Value>
DataSaver &operator<<(DataSaver &out, const BinaryTreeMap<Key, Value> &tree)
{
	return out<<tree.tree;
}

template<class Key, class Value>
DataLoader &operator>>(DataLoader &in, typename BinaryTreeMap<Key, Value>::Entry &entry)
{
	return in>>entry.key>>entry.value;
}

template<class Key, class Value>
DataSaver &operator<<(DataSaver &out, const typename BinaryTreeMap<Key, Value>::Entry &entry)
{
	return out<<entry.key<<entry.value;
}

...


And the definition of BinaryTree:
1
2
3
4
5
6
7
8
template<class T>
class BinaryTree
{
....
	friend DataSaver &operator<< <T> (DataSaver &out, const BinaryTree<T> &t);
	friend DataLoader &operator>> <T> (DataLoader &in, BinaryTree<T> &t);
...
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
template<class T>
DataLoader &operator>>(DataLoader &in, BinaryTree<T> &t)
{{
...
			T data;
			in>>data;
...
}

template<class T>
DataSaver &operator<<(DataSaver &out, const BinaryTree<T> &t)
{
...
			out<<n->data;
...
}


For some reason I don't understyand, when I try to input/output a BinaryTreeMap, it can't find the operators for the Entry. Any ideas why?
Have you tried defining the functions inline within the class?
Have you tried defining the functions inline within the class?


You can't, AFAIK. They are global so you'd have to put them outside.

Make sure all the template functions are in the header file. You can't have templated functions in the .cpp.

You should also add
1
2
template <class Key, class Value>
DataLoader &operator>>(DataLoader &in, BinaryTreeMap<Key, Value> &tree);


in a line *before* the declaration of class BinaryTreeMap (*outside* the binary tree class).

Btw, I had the exact same issue yesterday on this http://www.cplusplus.com/forum/general/26588/ post.
Last edited on
1) The first code section is from BinaryTreeMap.h
2) The other 2 code snippets are from BinaryTree.h
3) BinaryTreeMap.h has an include for BinaryTree.h
4) The code which uses operator>> and operator<< for BinaryTreeMap has an include for BinaryTreeMap.h

So tition's suggestion to add the code is irrelevant - that's where the definition is. I have tried to place declarations for the operator<< and operator>> of BinaryTreeMap<Key,Value>::Entry befoire the include, but that also won't compile.
tition's post is right. I fixed a similar issue in my colleague's code before. Your code 2, 3 does not have tition's post included.

BTW, you'd also have to forward declare BinaryTreeMap before the code as tition's posted.

I'd suggest trying out a suggestion before dismissing it, and also posting some simpler and ready-to-try-out code (including adding ; to end of class defs, comment out ...)
Last edited on
Adding the following code doesn't solve the problem:
1
2
3
4
5
6
7
8
9
10
11
12
class DataLoader;
class DataSaver;
template<class Key, class Value>
class BinaryTreeMap;
template<class Key, class Value>
DataLoader &operator>>(DataLoader &in, BinaryTreeMap<Key, Value> &tree);
template<class Key, class Value>
DataSaver &operator<<(DataSaver &out, const BinaryTreeMap<Key, Value> &tree);
template<class Key, class Value>
DataLoader &operator>>(DataLoader &in, typename BinaryTreeMap<Key, Value>::Entry &entry);
template<class Key, class Value>
DataSaver &operator<<(DataSaver &out, const typename BinaryTreeMap<Key, Value>::Entry &entry);


Note that tition's code is included in this.
Hi again, what is your definition of DataLoader?

What error messages do you get? Which compiler do you use? (I used the latest version of gcc)
Last edited on
I'm using:
1
2
3
4
5
6
7
8
9
Microsoft Visual Studio 2010
Version 10.0.30319.1 RTMRel
Microsoft .NET Framework
Version 4.0.30319 RTMRel

Installed Version: VC Express

Microsoft Visual C++ 2010   01013-169-2610014-70199
Microsoft Visual C++ 2010


The error I'm getting is:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
Filename(line number) error 2679: binary '>>' : no operator found which takes a right-hand operand of type 'BinaryTreeMap<Key,Value>::Entry' (or there is no acceptable conversion)
          with
          [
              Key=String,
              Value=FileHandler::Section
          ]
          Filename (line number) could be 'DataLoader &operator >>(DataLoader &,String &)'
          Filename (line number) or (other possibility) [etc. - 15 vmore possibilities]
          c:\users\owner\documents\visual studio 2010\projects\project1\project1\binarytreemap.h(33) : see reference to function template instantiation 'DataLoader &operator >><BinaryTreeMap<Key,Value>::Entry>(DataLoader &,BinaryTree<T> &)' being compiled
          with
          [
              Key=String,
              Value=FileHandler::Section,
              T=BinaryTreeMap<String,FileHandler::Section>::Entry
          ]
          c:\users\owner\documents\visual studio 2010\projects\project1\project1\filehandler.cpp(51) : see reference to function template instantiation 'DataLoader &operator >><Key,Value>(DataLoader &,BinaryTreeMap<Key,Value> &)' being compiled
          with
          [
              Key=String,
              Value=FileHandler::Section
          ]


As to the definition of DataLoader, it's defined to handle all primitivew data types other than pointers, and various classes also give it an input operator.
Alright, I gave it a try on my rusty Windows with Visual studio.

The below compiles like a charm. I substituted the unknown DataLoader class with a std::stringstream. For sure I am completely on your side: I think your code (the parts you posted) appear to be good.

Important: if you change line 20 to return out << 1; it DOES NOT compile. This appears at first glance to be a compiler issue.


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
#include<iostream>
#include<sstream>

template<class Key, class Value>
class BinaryTreeMap;

template<class Key, class Value>
std::stringstream &operator<< (std::stringstream& out, const BinaryTreeMap<Key, Value> &element);

template<class Key, class Value>
class BinaryTreeMap
{
private:
  friend std::stringstream& operator<< <Key,Value>(std::stringstream& out, const BinaryTreeMap<Key, Value>& element);
};

template<class Key, class Value>
std::stringstream& operator<<(std::stringstream& out, const BinaryTreeMap<Key, Value>& element)
{ out << 1;
  return out;
}

int main()
{ BinaryTreeMap<int, int> x;
  std::stringstream out;
  out << x;
  std::string tempS=out.str();
  std::cout<< out.str();
  std::cin>> tempS;
  return 0;
}


[Edit:] Important: If you change line 26 to out <<x <<x; it again doesn't compile. I think in gcc it wouldn't compile either, but if you put the brackets like this (out <<x) <<x; I think it did compile (not 100% sure). On my version of visual studio, the brackets do not appear to change anything.

Any other observations on the issue?
Cheers
Last edited on
The weak point, which fails to copile, appears tpo be the step from BinaryTree<BinaryTreeMap<Key, Value>::Entry> (a single template parameter) to BinaryTreeMap<Key, Value>::Entry (with 2 template parameters).

I have changed the input/output operators to the following:
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
template<class Key, class Value>
DataLoader &operator>>(DataLoader &in, BinaryTreeMap<Key, Value> &tree)
{
	in>>tree.tree;
	return in;
}

template<class Key, class Value>
DataSaver &operator<<(DataSaver &out, const BinaryTreeMap<Key, Value> &tree)
{
	out<<tree.tree;
	return out;
}

template<class Key, class Value>
DataLoader &operator>>(DataLoader &in, typename BinaryTreeMap<Key, Value>::Entry &entry)
{
	in>>entry.key;
	in>>entry.value;
	return in;
}

template<class Key, class Value>
DataSaver &operator<<(DataSaver &out, const typename BinaryTreeMap<Key, Value>::Entry &entry)
{
	out<<entry.key;
	out<<entry.value;
	return out;
}


It still won't compile - same reason.
This problem comes up from time to time:
1
2
3
4
5
6
template<class Key, class Value>
DataLoader &operator>>(DataLoader &in, typename BinaryTreeMap<Key, Value>::Entry &entry)
{
	return in>>entry.key>>entry.value;
}


Parameters of the form Template_Class<>::sub_type are not suitable for template argument deduction.
Which means this argument typename BinaryTreeMap<Key, Value>::Entry &entry will
not be used by the compiler to deduce Key or Value template parameters
I do not have the visual studio compiler in front of me to experiment, however it appears to me that the compiler has a problem figuring out that Entry is a templated class.

Although that appears to be conceptually different, I would do it like this:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
template <class Key, class Value>
struct Entry
{
  Key key;
  Value value;
};

template<class Key, class Value>
class BinaryTreeMap;
template<class Entry>
class BinaryTree;

template<class Key, class Value>
std::stringstream &operator>>(std::stringstream  &in, Entry<Key, Value> &entry);

template<class Key, class Value>
class BinaryTreeMap
{
private:
  BinaryTree<Entry<Key, Value> > tree;
  friend std::stringstream & operator >><Key, Value>(std::stringstream  &in, Entry<Key, Value> &entry);
};


Not 100% sure for the syntax, but I think the idea is clear: take the Entry out of the BinaryTreeMap class. It is then no longer subjugate to the BinaryTreeMap class (which is not desired) but for all practical purposes it appears to do the same thing.


Last edited on
Thank you, this works.
Topic archived. No new replies allowed.