template confusion


I would like to apply the same type to a friend operator>> function.
Not sure how though, and the following compile appears:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
c++ -g -std=c++14 -pedantic -Wall -Wpointer-arith -Wwrite-strings -Wcast-qual -Wcast-align -Wformat-security -Wformat-nonliteral -Wmissing-format-attribute -Winline -funsigned-char "test_load_edges.cpp" (in directory: /home/bluefrog/course/advanced_algorithms/project)
test_load_edges.cpp:55:96: warning: friend declaration ‘std::ostream& operator<<(std::ostream&, const std::map<T, std::vector<k> >&)’ declares a non-template function [-Wnon-template-friend]
     friend std::ostream & operator<<(std::ostream & os, const std::map <T, std::vector<T> > & m);
                                                                                                ^
test_load_edges.cpp:55:96: note: (if this is not what you intended, make sure the function template has already been declared and add <> after the function name here)
test_load_edges.cpp: In function ‘int main()’:
test_load_edges.cpp:65:3: error: ‘cout’ was not declared in this scope
   cout << g;
   ^
test_load_edges.cpp:65:3: note: suggested alternative:
In file included from test_load_edges.cpp:2:0:
/usr/include/c++/5/iostream:61:18: note:   ‘std::cout’
   extern ostream cout;  /// Linked to standard output
                  ^
Compilation failed.


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
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
#include <string>       // std::string
#include <iostream>     // std::cout
#include <sstream>      // std::stringstream
#include <cstdint>
#include <map>
#include <vector>

template<class k, class v>
using mi = typename std::map<k,v>::const_iterator;

template<class k>
using vi = typename std::vector<k>::const_iterator;

template<class k, class v>
std::ostream & operator<<(std::ostream & os, const std::map<k, v> & m) {

  // header
  std::vector<k> header;
  for (mi<k,v> it = begin(m); it != end(m); ++it) {
    header.push_back(it->first);
    os << it->first << " ";
  }

  os << "\n";

  // body
  for (mi<k,v> it = begin(m); it != end(m); it++) {
    os << it->first << "|";
    std::vector<k> path = it->second;
    for (vi<k> i = begin(path); i != end(path); ++i)
      os << *i << ' ';
  }

  return os;
}

template <class T>
class Graph {

  std::map <T, std::vector<T> > adjacency_list;
  int v1,v2;

  public:
    Graph() { }
    ~Graph() { }

    void create_adjacency_list(std::istream & stm) {
      while (stm >> v1 >> v2) {
        // std::cout << "Edge : " << v1 << ", " << v2 << "\n";
        adjacency_list[v1];
        adjacency_list[v1].push_back(v2);
      }
    }

    friend std::ostream & operator<<(std::ostream & os, const std::map <T, std::vector<T> > & m);
  
};

int main() {
  std::istringstream  vertices {"1 2  2 3  3 1  4 1  4 5  5 3  5 6  5 7  5 8  6 4  7 6  8 9  9 10  10 6"};

  Graph<uint_fast8_t> g;
  g.create_adjacency_list(vertices);

  cout << g;

  return 0;

}


Can anybody suggest how to include the operator>> friend function into the class ?
thanks
Where have you implemented that overload?

By the way line 65 is looking for an overload for the ostream class for a Graph, not a std::map, plus you forgot to properly scope this function.



That was just a warning, you typed cout instead of std::cout.

test_load_edges.cpp:65:3: error: ‘cout’ was not declared in this scope
cout << g;

Last edited on
You are trying to create a bound template friend operator << for class Graph i.e. the type of the friend is determined by the type of the class when the class is instantiated. This can be done in the following order:

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
template <class T> class Graph; // 1. forward declare class Graph

template<typename T>
std::ostream & operator<<(std::ostream & os, const Graph<T> &g);//2. declare template operator <<

template <class T> class Graph	//
{
  std::map <T, std::vector<T> > adjacency_list;
  int v1,v2;

  public:
    Graph() { }
    ~Graph() { }
	 ... 
    friend std::ostream & operator<< <>(std::ostream & os, const Graph<T> & g);
//3. declare bound template friend operator <<, the <> in the declaration identifies the template specialization
};
//4. define full template functions
template <typename T> std::ostream & operator<< (std::ostream & os, const Graph<T>  & g)
{
    for (auto& elem : g.adjacency_list)
    os<<elem.first<<"\n";
    for(auto& elem_v : elem.second)
    {
        os<<elem_v<<"\n";
    }
    return os;
}

Finally solved, so I thought I'd post solution for any comments.


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
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
#include <string>       // std::string
#include <iostream>     // std::cout
#include <sstream>      // std::stringstream
#include <cstdint>
#include <map>
#include <vector>

template <typename T> class Graph;

template <class T>
class Graph {

  using adjacency_list = std::map< T, std::vector<T> >;
  adjacency_list al;
  int v1,v2;

  public:
    Graph() { }
    ~Graph() { }

    void create_adjacency_list(std::istream & stm) {
      while (stm >> v1 >> v2) {
        al[v1];
        al[v2]; // a key might not any outbounds, so v2 has to be included just in case there are not outbounds
                // no duplicates will be created, since the key is unique
        al[v1].push_back(v2);
      }
    }

    template <class Y> // class name has to be different, otherwise shadow errors appear
    friend std::ostream & operator<<(std::ostream & os, const Graph<Y> & g);

};


template<class Y>
std::ostream & operator<<(std::ostream & os, const Graph<Y> & g) {
	// header
  os << "  ";
	for (const auto & p : g.al) {
		os << p.first << "  ";
	}

	os << "\n";

	// body
	for (const auto & p : g.al) {
		os << p.first << "|";
		for (auto i = begin(p.second); i != end(p.second); ++i)
			os << *i << "  ";
    os << "\n";
	}

	return os;
}


int main() {
  std::istringstream  vertices {"1 2  2 3  3 1  4 1  4 5  5 3  5 6  5 7  5 8  6 4  7 6  8 9  9 10"};

  Graph<unsigned short> g;
  g.create_adjacency_list(vertices);

  std::cout << g;

  return 0;

}
Last edited on
Topic archived. No new replies allowed.