unable to access friend function in template class - c++

The Pairwise class represents a pair with a key:value. I've made a template pair and was having errors trying to run with a key and value input to the class and printing it out.
Given my main:
#include "file_name.h"
int main (){
Pairwise<string, string> example = {{"key", "value"}};
cout << example << endl;
}
And my header file:
#pragma once
#include<iostream>
using std::ostream; using std::cout; using std::endl;
#include<string>
using std::string;
#include<utility>
using std::pair;
#include<sstream>
using std::ostringstream;
template<typename K, typename V>
struct Pairwise{
K first;
V second;
Pairwise() = default;
Pairwise(K, V);
//print out as a string in main
friend ostream& operator<<(ostream &out, const Pairwise &n) {
ostream oss;
string s;
oss << n.first + ":" + n.second; //possible error?
s = oss.str();
out << s;
return out;
}
};
My expected output after running main would be:
key:value
However, I am getting the error:
h:28:11: error: 'std::basic_ostream<_CharT, _Traits> is protected within..."

h:25:59: friend declaration delares a non template function.
You are missing to declare the function as a template that takes Pairwise<K, V>:
header.h:
#ifndef HEADER_H_INCLUDED /* or pragma once */
#define HEADER_H_INCLUDED /* if you like it */
#include <iostream> // or <ostream>
template<typename K, typename V>
class Pairwise { // made it a class so that the
K first; // friend actually makes sense.
V second;
public:
Pairwise() = default;
Pairwise(K first, V second)
: first{ first }, second{ second }
{}
template<typename K, typename V>
friend std::ostream& operator<<(std::ostream &out, Pairwise<K, V> const &p)
{
return out << p.first << ": " << p.second;
}
};
#endif /* HEADER_H_INCLUDED */
source file:
#include <iostream> // the user can't know a random header includes it
#include <string>
#include "header.h"
int main()
{
Pairwise<std::string, std::string> p{ "foo", "bar" };
std::cout << p << '\n';
}
Sidenote: You could also use
{
using Stringpair = Pairwise<std::string, std::string>;
// ...
Stringpair sp{ "foo", "bar" };
}
if you need that more often.
The other errors you got result from confusing std::ostringstream with std::ostream in operator<<().

As you write it, you define the operator as a member function, which is very likely not intended. Divide it like ...
template<typename K, typename V>
struct Pairwise{
K first;
V second;
Pairwise() = default;
Pairwise(K, V);
//print out as a string in main
friend ostream& operator<<(ostream &out, const Pairwise &n);
};
template<typename K, typename V>
ostream& operator<<(ostream &out, const Pairwise<K,V> &n) {
...
return out;
}
And it should work.
BTW: Note that in a struct all members are public by default; so you would be able to access them even in absence of the friend-declaration.

In c++, less is often more...
#pragma once
#include<iostream>
#include<string>
// never do this in a header file:
// using std::ostream;
template<typename K, typename V>
struct Pairwise{
K first;
V second;
Pairwise() = default;
Pairwise(K, V);
//print out as a string in main
friend std::ostream& operator<<(std::ostream &out, const Pairwise &n) {
return out << n.first << ':' << n.second;
}
};
int main (){
using std::cout; using std::endl; using std::string;
Pairwise<string, string> example = {"key", "value"};
cout << example << endl;
}
https://godbolt.org/z/ZUlLTu

Related

Overloading the output operator for a template class and a nested class

There is a template class in which a subclass is nested. How to properly overload the output operator to the stream for an external class, which is a template, in which the output operator to the stream is called from a nested class? In my case, compilation errors occur:
no type named 'type' in 'struct std::enable_if<false, void>'
no match for 'operator<<' (operand types are 'std::basic_ostream' and 'Nesting::Nested')
I give my code below.
#include <iostream>
#include <string>
using namespace std;
template<typename T>
class Nesting {
public:
class Nested {
public:
T data;
Nested(const T & data): data(data) {;}
template<typename U>
friend ostream & operator<<(ostream & out, const typename Nesting<U>::Nested & nested);
};
T data;
Nested * pNested;
Nesting(const T & data)
: data(data)
, pNested(new Nested(222)) {;}
template<typename U>
friend ostream & operator<<(ostream & out, const Nesting<U> & nesting);
};
template<typename T>
ostream & operator<<(ostream & out, const typename Nesting<T>::Nested & nested) {
out << "Nested: " << nested.data;
return out;
}
template<typename T>
ostream & operator<<(ostream & out, const Nesting<T> & nesting) {
out << "Nesting: " << nesting.data << ", " << *nesting.pNested << endl;
return out;
}
int main() {
Nesting<int> n(111);
cout << n << endl;
return 0;
}
I think the easiest thing to do is to provide the definition inline with the declaration.
#include <iostream>
#include <memory>
#include <string>
using std::cout;
using std::make_unique;
using std::ostream;
using std::unique_ptr;
template<typename T>
class Nesting {
public:
class Nested {
public:
T data;
Nested(T const& data_): data{data_} {}
friend auto operator<<(ostream& out, Nested const& nested) -> ostream& {
return out << "Nested: " << nested.data;
}
};
T data;
unique_ptr<Nested> pNested;
Nesting(T const& data_)
: data{data_}
, pNested{make_unique<Nested>(222)} {}
friend auto operator<<(ostream& out, Nesting const& nesting) -> ostream& {
return out << "Nesting: " << nesting.data << ", " << *nesting.pNested;
}
};
int main() {
Nesting<int> n(111);
cout << n << "\n";
}
You can add a wrapper to remove the dependant type deduction. Something like:
template<typename T>
struct NestingNested
{
const Nesting<T>::Nested & nested;
template<typename U>
friend std::ostream & operator<<(std::ostream & out, const NestingNested<U> & nested);
};
template<typename T>
std::ostream & operator<<(std::ostream & out, const NestingNested<T> & nested) {
out << "Nested: " << nested.nested.data;
return out;
}
template<typename T>
std::ostream & operator<<(std::ostream & out, const Nesting<T> & nesting) {
out << "Nesting: " << nesting.data << ", " << NestingNested<T>{ *nesting.pNested } << std::endl;
return out;
}
Compiler Explorer

Overriding << operator for templated struct

numcpp.h file
#include "iostream"
namespace numcpp{
template<typename T>
struct Vector
{
std::vector<T> v;
};
template<typename T>
struct Matrix
{
std::vector<T> m;
//template<typename T>
friend std::ostream& operator << (std::ostream& out, const mf& mat);
};
typedef Vector<float> vf;
typedef Matrix<vf> mf;
}
I am trying to overload << operator for cout to be able to print mf. First I tried making the overloading function a friend that directly takes mf as argument. I did this because if I took Matrix as argument, I would need to deal with template and I don't know how to do that.
numcpp.cpp file
#include "numcpp.h"
namespace numcpp{
std::ostream& operator << (std::ostream& out, const mf& mat)
{
//overloaded out here
return out;
}
}
main.cpp
#include "iostream"
#include "numcpp.h"
int main()
{
numcpp::mf inputs;
// inputs is filled with random numbers here
std::cout << inputs;
}
But this gives an error identified mf is undefined in .h file in line friend std::ostream& operator << (std::ostream& out, const mf& mat);
So I ditched this approach and tried removing the friend function declaration from Matrix without changing the .cpp file. But now I get a different error saying no operator << matches these operands.
I think this is because the overload is done in numcpp namespace so it is not visible from main which is outside the namesapce.
What you normally want is to define a template in your header file. The definition needs to be available at the call-site to allow the compiler to make an instatiation of the template.
If possible, the easiest way is to put the definition in the class definition.
template<typename T>
struct Matrix
{
std::vector<T> m;
// using Matrix here is allowed and refers to the current instatiation, equivalent to writing Matrix<T>
friend std::ostream& operator << (std::ostream& out, const Matrix& mat) {
...
return out;
}
};
Try change your numcpp.h to
namespace numcpp{
template<typename T>
struct Vector
{
std::vector<T> v;
};
typedef Vector<float> vf;
template<typename T>
struct Matrix
{
std::vector<T> m;
//template<typename T>
inline friend std::ostream& operator << (std::ostream& out, const Matrix<vf>& mat);
};
inline std::ostream& operator << (std::ostream& out, const Matrix<vf>& mat)
{
//overloaded out here
return out;
}
typedef Matrix<vf> mf;
}
You are getting this error because mf was not declared when you trying to use it.
Also, you can add the body of the function directly in the definition to get rid of the inline.
The typedefs are not available inside the definition of your class Matrix. You can either declare the typedef before the class definition (#Alloces' answer) of just template the overloaded operator:
#include <vector>
#include <sstream>
#include <iostream>
namespace numcpp {
template<typename T>
struct Vector
{
std::vector<T> v;
};
template<typename T>
struct Matrix
{
std::vector<T> m;
template<typename K> // template parameter must not be named T
inline friend std::ostream& operator << (std::ostream& out, const Matrix<K>& mat);
};
template<typename K>
inline std::ostream& operator << (std::ostream& out, const Matrix<K>& mat)
{
return out << "Just a test";
}
typedef Vector<float> vf;
typedef Matrix<vf> mf;
}
int main() {
numcpp::mf inputs;
std::cout << inputs << "\n"; // Just a test
}

Print pair without introducing wrappers

I know that I could introduce wrapper(proxy class) to wrap pair and add overloaded << operator, but I I'am wondering why introducing '<<' operator for std namespace like below do not work?
#include <iostream>
#include <iterator>
#include <vector>
#include <algorithm>
namespace std{
ostream& operator<<(ostream& os, pair<int, int>&);
}
std::ostream& std::operator<<(std::ostream& os, std::pair<int, int>& pi){
os << pi.first <<", " << pi.second;
return os;
}
int main(){
std::vector< std::pair<int, int> > pi;
pi.push_back(std::make_pair(1,2));
std::cout << pi.front<<std::endl;
}
This is illegal:
namespace std{
ostream& operator<<(ostream& os, pair<int, int>&);
}
you may only specialise a template class for function in the std namespace for user defined types.
You may not add overloads for user defined types to the std namespace.
This is an overload in namespace std.
anticipating:
but what is the correct way?
This is:
#include <iostream>
#include <iterator>
#include <vector>
#include <algorithm>
template<class T>
struct tuple_printer;
template<class T>
auto tuple_print(const T& t) {
return tuple_printer<std::decay_t<T>>(t);
}
template<class T>
struct tuple_printer
{
tuple_printer(const T& t) : _t(t) {}
void operator()(std::ostream& os) const {
os << _t;
}
const T& _t;
};
template<class X, class Y>
struct tuple_printer<std::pair<X, Y>>
{
using arg_type = std::pair<X, Y>;
tuple_printer(const arg_type& t) : _t(t) {}
void operator()(std::ostream& os) const {
os << '(' << tuple_print(_t.first) << ", " << tuple_print(_t.second) << ')';
}
const arg_type& _t;
};
template<class T, class A>
struct tuple_printer<std::vector<T, A>>
{
using arg_type = std::vector<T, A>;
tuple_printer(const arg_type& t) : _t(t) {}
void operator()(std::ostream& os) const {
auto sep = " ";
os << '[';
for (const auto& e : _t) {
os << sep << tuple_print(e);
sep = ", ";
}
os << " ]";
}
const arg_type& _t;
};
template<class T>
std::ostream& operator<<(std::ostream& os, const tuple_printer<T>& tp){
tp(os);
return os;
}
int main(){
std::vector< std::pair<int, int> > pi;
pi.push_back(std::make_pair(1,2));
pi.push_back(std::make_pair(3, 4));
std::cout << tuple_print(pi.front()) << std::endl;
std::cout << tuple_print(pi) << std::endl;
return 0;
}
expected output:
(1, 2)
[ (1, 2), (3, 4) ]
Perfect, eh?
You have a simple typo in your code:
std::vector< std::pair<int, int> > pi;
pi.push_back(std::make_pair(1,2));
std::cout << pi.front<<std::endl;
The last line should read:
std::cout << pi.front() <<std::endl;
note the difference between std::pair<X,Y>::front and std::vector<X>::front().
As a side note, you should probably make your operator<< accept a const pair.

I am having trouble with a simple argument dependent lookup / template type inferencing issue

I have this snippet of code and I do not understand why the std::cout line is not compiling... The argument lookup / template argument inferencing seems correct...
#include <iostream>
template<typename T>
struct A
{
struct M1
{
T x;
};
};
template<typename T>
std::ostream &operator<<(std::ostream &os, typename A<T>::M1 const &o)
{
os << o.x;
return os;
}
int main()
{
A<int>::M1 a;
std::cout << a; // This line fails
return 0;
}
BTW I'm trying to do this without a declaring operator<<() as an inline function.
Your problem is that T is in a non deduced context. C++ will only simple pattern match, it will not invert possibly arbitrary type maps.
Imagine there was a specialization of A<void> that set using M1=A<int>::M1. Now both int and void are valid T for your <<. As the problem is intractible in general, C++ refuses to even try: you can only pattern match on direct template arguments of your argument types.
To do what you really want:
template<typename T>
struct A {
struct M1 {
T x;
friend std::ostream& operator<<(std::ostream& os, M1 const& m1){
return os << m1.x;
}
};
};
Learn to love Koenig operators.
The template parameter T of your operator cannot be deduced. However, there is some workaround using some SFINAE magic:
#include <iostream>
template<typename T>
struct A {
struct M1 {
using type = T;
T x;
};
};
template<typename T, std::enable_if_t<std::is_same<T, typename A<typename T::type>::M1>::value, int> = 0>
std::ostream &operator<<(std::ostream &os, const T& o)
{
os << o.x;
return os;
}
int main()
{
A<int>::M1 a;
std::cout << a; // This line works
return 0;
}

template classes as template parameters

How to define a function template-ed on a container and a type?
For example, overload insertion operator to stream all the elements of a vector, list, or, forward iterator container:
using namespace std;
#include <iostream>
#include <vector>
#include <list>
//...
//...the second argument is a container template-ed on type T
//...
template <typename T,template <typename U> class C>
ostream&
operator<<
(ostream& p_os,const C<T>& p_c)
{
for(typename C<typename T>::const_iterator cit=p_c.begin();cit!=p_c.end();++cit)
{
p_os.operator<<(*cit);
}
return p_os;
}
int
main
()
{
vector<int> v;
cout << v << endl;
list<int> l;
cout << l << endl;
return 0;
}
This does not compile on g++ 4.9. What is wrong? How is it done?
Why not just pass the container type as template parameter, and find out the element type from it? In your example code you don't even need the element type:
template <typename C>
ostream&
operator<<
(ostream& p_os,const C& p_c)
{
typedef typename C::value_type element_type; // if needed
for(typename C::const_iterator cit=p_c.begin();cit!=p_c.end();++cit)
{
p_os.operator<<(*cit);
}
return p_os;
}
(Although it might be unwise to use this for global functions like this without some enable_if trickery, since it will otherwise match any argument.)
EDIT: You could for example attempt to restrict this to classes with a nested value_type (which all containers have):
template <typename C, typename T = typename C::value_type>
ostream&
operator<<
(ostream& p_os,const C& p_c)
std::vector is a class template that has two template type parameters:
template <class T, class Alloc = allocator<T> >
class vector;
To make your function working with std::vector (and other two-parameter class templates) you can use the following definition:
template <typename T, typename A, template <typename, typename> class C>
// ~~~~~~~~~^ ~~~~~~~^
ostream& operator<<(ostream& p_os, const C<T,A>& p_c)
// ^^
{
for(typename C<T,A>::const_iterator cit=p_c.begin();cit!=p_c.end();++cit)
{
p_os.operator<<(*cit);
}
return p_os;
}
or alternatively:
template <typename T, template <typename...> class C>
ostream& operator<<(ostream& p_os, const C<T>& p_c);
Alan Stokes approach works. The code below can stream any container. I just had to add an insertion operator for maps
using namespace std;
#include <iostream>
#include <vector>
#include <list>
#include <forward_list>
#include <set>
#include <deque>
#include <array>
#include <map>
#include <unordered_map>
//...
//...needed for map types which are (key,value) pairs.
//...
template <typename K,typename V>
ostream&
operator<<
(ostream& p_os,const pair<const K,V>& p_v)
{
std::operator<<(p_os,'(');
p_os << p_v.first;
std::operator<<(p_os,',');
p_os << p_v.second;
std::operator<<(p_os,')');
return p_os;
}
template <typename C, typename T = typename C::iterator>
ostream&
operator<<
(ostream& p_os,const C& p_c)
{
for(typename C::const_iterator cit=p_c.begin();cit!=p_c.end();++cit)
{
typename C::value_type v = *cit;
p_os << v;
std::operator<<(p_os,",");
}
return p_os;
}
int
main
()
{
vector<int> v;
for(int i=0;i<4;++i)
{
v.push_back(i);
}
cout << v << endl;
list<int> l;
for(int i=0;i<4;++i)
{
l.push_back(i);
}
cout << l << endl;
forward_list<int> fl = {0,1,2,3};
cout << fl << endl;
set<int> s;
for(int i=0;i<4;++i)
{
s.insert(i);
}
cout << s << endl;
deque<int> d;
for(int i=0;i<4;++i)
{
d.push_back(i);
}
cout << d << endl;
array<int,4> a = {0,1,2,3};
cout << a << endl;
unordered_map<int,int> um;
for(int i=0;i<4;++i)
{
um[i] = i;
}
cout << um << endl;
map<int,int> m;
for(int i=0;i<4;++i)
{
m[i] = i;
}
cout << m << endl;
return 0;
}