template confusion
Nov 26, 2016 at 4:51pm UTC
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
Nov 26, 2016 at 5:41pm UTC
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.
Nov 26, 2016 at 5:51pm UTC
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 Nov 26, 2016 at 5:51pm UTC
Nov 27, 2016 at 1:12am UTC
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;
}
Nov 27, 2016 at 1:21am UTC
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 Nov 27, 2016 at 1:21am UTC
Topic archived. No new replies allowed.