I'm trying to overload << operator for some template class
#include <iostream>
#include <iterator>
#include <map>
template <typename T1, typename T2>
class SampleClass {
public:
SampleClass() = default;
void Add(const T1 &key, const T2 &value)
{
database[key] = value;
}
typename std::map<T1, T2>::const_iterator cbegin() const { return database.cbegin(); }
typename std::map<T1, T2>::const_iterator cend() const { return database.cend(); }
private:
std::map<T1, T2> database;
};
template <typename T1, typename T2>
std::ostream &operator << (std::ostream &os, SampleClass<T1, T2> &rhs)
{
for(auto el = rhs.cbegin(); el != rhs.cend(); el++)
os << el->first << " " << el->second << std::endl;
return os;
}
The error that I'm getting from g++
error: cannot bind ‘std::basic_ostream<char>’ lvalue to ‘std::basic_ostream<char>&&’
os << el->first << " " << el->second << std::endl;
I tried also declaring this operator as inline friend function but the result it the same also didn't work. Could anyone explain to me why it happens??
Update:
The thing is the compiler didn't tell me that the cass which i used as the value for the SampleClass didn't have overloaded << operator. I was still looking around in the SampleClass instead of checking other files. But thanks to you that told me that for built in types everything is ok i realized what is needed to be checked. Thank you and sorry for trouble.
Related
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
So I overloaded the ostream << operator so it can take most STL containers and print them. However, it doesn't work for passing strings (the error is "ambiguous overload" for the line "cout << s;"). How do I make it so it works on strings as if it weren't overloaded?
#include <bits/stdc++.h>
using namespace std;
template<typename T>
ostream& _containerprint(ostream &out, T const &val) {
return (out << val << " ");
}
template<typename T1, typename T2>
ostream& _containerprint(ostream &out, pair<T1, T2> const &val) {
return (out << "{" << val.first << " " << val.second << "} ");
}
template<template<typename, typename...> class TT, typename... Args>
ostream& operator<<(ostream &out, TT<Args...> const &cont) {
for(auto&& elem : cont) {
_containerprint(out, elem);
}
return out;
}
int main() {
string s = "help me";
cout << s;
}
Edit: please stop freaking out, the #include <bits/stdc++.h> is because it's for a programming contest setting; it really doesn't matter!
std::string is a template class (alias of std::basic_string<char>)
so std::cout << s match your overload and the one for std::basic_string<T>.
And none overload is more specialized than the other.
Possible workaround is to add additional overload for std::string:
std::ostream& operator << (std::ostream& out, const std::string& s)
{
return operator << <char>(out, s);
// Select template <class CharT, class Traits, class Allocator>
// std::basic_ostream<CharT, Traits>&
// operator<<(std::basic_ostream<CharT, Traits>& os,
// const std::basic_string<CharT, Traits, Allocator>& str);
}
Demo
Make your ostream parameter more general so that your overload is more general than the standard one for std::string.
template<typename CharT, typename Traits, typename T>
ostream& _containerprint(std::basic_ostream<CharT, Traits> &out, T const &val) {
return (out << val << " ");
}
template<typename CharT, typename Traits, typename T1, typename T2>
ostream& _containerprint(std::basic_ostream<CharT, Traits> &out, pair<T1, T2> const &val) {
return (out << "{" << val.first << " " << val.second << "} ");
}
template<typename CharT, typename Traits, template<typename, typename...> class TT, typename... Args>
ostream& operator<<(std::basic_ostream<CharT, Traits> &out, TT<Args...> const &cont) {
for(auto&& elem : cont) {
_containerprint(out, elem);
}
return out;
}
Why following code produces compilation error?
#include <iostream>
#include "gtest/gtest.h"
#include <utility>
namespace A {
//overloading operator << for std::pair
template<typename T1, typename T2>
std::ostream& operator<<(std::ostream& os, const std::pair<T1, T2>& p) {
return os << "pair:{" << p.first << ", " << p.second << "}";
}
struct C {
int x;
};
std::ostream& operator<<(std::ostream& os, const C& c) {
return os << c.x;
}
TEST(TestA, testA) {
std::pair<C, C> pair1;
std::pair<int, int> pair2;
EXPECT_EQ(0, 0) << pair1; //compiles
EXPECT_EQ(0, 0) << pair2; //doesn't compile
}
}
I use Visual Studio 2015. Error text is:
Error C2679 binary '<<': no operator found which takes a right-hand
operand of type 'const std::pair' (or there is no acceptable
conversion) ...\gtest\gtest-message.h 131
How changing user-defined type to built-in type makes a difference?
Upd. Thanks to #Kerrek SB, error is explained. However, now there is another question: How should I overload operator<< for std::pair to be able to use it like in my code?
When one writes something like EXPECT_EQ(e1,e2) << some_pair, the template function
template<typename T>
::testing::Message::operator<<
is being instantiated. Only inside this function user-defined operator<< is being called. Because function resides in another namespace (not in A) user-defined operator<< can't be found.
Solution is easy. Gtest offers function ::testing::PrintToString which accepts STL containers. So the code should be like this (I changed it to make sense):
EXPECT_TRUE(some_predicate(pair2)) << ::testing::PrintToString(pair2);
I took your answer and turned it into a minimal example, removing the dependence on the Google code:
#include <iostream>
namespace A {
template<typename T1, typename T2>
std::ostream& operator<<(std::ostream& os, const std::pair<T1, T2>& p) {
return os << "pair:{" << p.first << ", " << p.second << "}";
}
struct C {
int x;
};
std::ostream& operator<<(std::ostream& os, const C& c) {
return os << c.x;
}
void test() {
std::pair<C, C> pair1;
std::pair<int, int> pair2;
std::cout << pair1 << std::endl; // compiles
std::cout << pair2 << std::endl; // also compiles
}
}
int main(int argc, char *argv[]) {
A::test();
}
This actually compiles fine for me, with the output
pair:{0, 0}
pair:{0, 0}
So, I cannot reproduce your problem. However, #KerrekSB has identified a good reason for your problem. I suspect the difference might lie in the fact that your code calls operator<< inside TEST, some type of macro defined by the Google Test package, while my more minimal example replaces this with a function in the namespace A, perhaps changing the name lookup?
You need to define operator << for std::pair in std namespace for gtest to find it.
The code as follows compiles fine:
#include <iostream>
#include "gtest/gtest.h"
#include <utility>
namespace std
{
//overloading operator << for std::pair
template<typename T1, typename T2>
ostream& operator<<(ostream& os, const pair<T1, T2>& p) {
return os << "pair:{" << p.first << ", " << p.second << "}";
}
}
namespace A {
struct C {
int x;
};
std::ostream& operator<<(std::ostream& os, const C& c) {
return os << c.x;
}
TEST(TestA, testA) {
std::pair<C, C> pair1;
std::pair<int, int> pair2;
EXPECT_EQ(0, 0) << pair1; //compiles
EXPECT_EQ(0, 0) << pair2; //compiles!
}
}
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.
Consider this code
#include <bits/stdc++.h>
using namespace std;
struct foo {
template <typename T>
foo& operator<< (const T& var) {
cout << var;
return *this;
}
} bar;
int main() {
bar << 1 << '\n';
bar << 1.2 << '\n';
return 0;
}
I want to overload << operator only for integer data types. (int16_t, int32_t, int64_t)
How can I do that?
You can use SFINAE to ensure that T is an integral type:
template <typename T>
std::enable_if_t<std::is_integral<T>::value, foo&>
operator<< (const T& var) {
cout << var;
return *this;
}
Alternatively, you can use static_assert:
template <typename T>
foo& operator<< (const T& var) {
static_assert(std::is_integral<T>::value, "T must be an integral type");
cout << var;
return *this;
}
Note that you should not #include anything from the bits folder, that's non-portable.
If you want separate overloads for integral and floating point types, you can make two overloads and select with SFINAE:
template <typename T>
std::enable_if_t<std::is_integral<T>::value, foo&>
operator<< (const T& var) {
cout << "int " << var;
return *this;
}
template <typename T>
std::enable_if_t<std::is_floating_point<T>::value, foo&>
operator<< (const T& var) {
cout << "float " << var;
return *this;
}
When we get Concepts you'll be able to write something like this:
template <Integral T>
// ^^^^^^^^ Integral rather than typename
foo& operator<< (const T& var) {
cout << var;
return *this;
}