I have a very simple inline helper class called IpAddress, which has 2 overloads of operator << to either serialize an object to a set of custom binary streams (operator as template function) or to output it to a std::ostream (non-template operator function).
#include <cstdint>
#include <string>
#include <array>
#include <iostream>
#include <sstream>
typedef uint8_t byte;
class IpAddress: public std::array<byte,4>
{
// ...
template<class S>
inline friend S& operator<<(S& left, const IpAddress& right) {
left.setBytes(right.data(), 4);
return left;
}
inline friend std::ostream& operator<< (std::ostream& left, const IpAddress& right) {
// do stuff eligible for an ostream
return left;
}
inline operator std::string() {
std::stringstream stream;
stream << *this;
return stream.str();
}
}
As you can see, there is also an operator to convert the address to a string. Unfortunately, the << call inside is selecting the wrong operator<< (the template one), leading to a compiler error:
error: C2039: 'setBytes' : is not a member of 'std::basic_stringstream<char,std::char_traits<char>,std::allocator<char>>'
Why is the compiler (MSVC in this case) selecting the wrong overload with a non-working body? Why not the "more specialized" std::ostream operator? How do I change this behaviour? Thanks!
You don't post a complete, compilable example so I can't see the call site.
However, the problem is most likely because whatever you are streaming out to is not exactly an ostream. It's likely to be derived from an ostream. In which case, template T will be a better match.
EDIT:
Style comments aside (they are right and you would do well to listen), here is a fix:
#include <iostream>
#include <utility>
#include <cstdint>
#include <array>
#include <sstream>
template<class T> static constexpr bool IsAnOstream = std::is_base_of<std::decay_t<T>, std::ostream>::value;
using byte = std::uint8_t;
struct IpAddress: public std::array<byte,4>
{
// ...
template<class S, std::enable_if_t<not IsAnOstream<S>>* = nullptr>
friend S& operator<<(S& left, const IpAddress& right) {
left.setBytes(right.data(), 4);
return left;
}
friend std::ostream& operator<< (std::ostream& left, const IpAddress& right) {
// do stuff eligible for an ostream
return left;
}
/*
* this is a bad idea - it can lead to all kinds of confusion
*
inline operator std::string() {
std::stringstream stream;
stream << *this;
return stream.str();
}
*/
};
// this is better - it's less surprising.
std::string to_string(const IpAddress& r)
{
std::stringstream stream;
stream << *this;
return stream.str();
}
struct MyStream
{
void setBytes(const uint8_t* p, size_t len) {}
};
int main()
{
IpAddress a;
MyStream s;
std::cout << a;
s << a;
return 0;
}
Related
I have learnt the operator<< can be overloaded by making it a friend function of class.
For example,
struct Test
{
std::string d_data;
Test(const std::string & data) : d_data{data} {}
friend std::ostream & operator<<(std::ostream & ostr, const Test & obj)
{
ostr << obj.d_data << '\n';
return ostr;
}
};
int main()
{
Test t1("one");
std::cout << t1;
Test t2("two");
std::cout << t2;
}
one
two
This seems to work as expected.
But, I'm unable to understand why the same isn't working for a global overload.
#include <iostream>
#include <ostream>
#include <string>
std::ostream & operator<<(std::ostream & os, const std::string & s)
{
os << s << '\n';
return os;
}
int main()
{
std::cout << "stackoverflow";
std::cout << "stackoverflow";
}
stackoverflowstackoverflow
Expected the strings to be separated by a newline, but didn't work as expected.
Your operator using
std::cout << "stackoverflow";
requires a user-defined conversion from an object of the type const char * (after the implicit conversion of the string literal to pointer to its first character) to an object of the type std::string.
However the standard basic_ostream class has already an operator that does not require such a conversion
template<class charT, class traits>
basic_ostream<charT, traits>& operator<<(basic_ostream<charT, traits>&, const char*);
So this operator is called instead of your operator.
Moreover within your operator
std::ostream & operator<<(std::ostream & os, const std::string & s)
{
os << s << '\n';
return os;
}
there is recursive calls of itself.
Your could define your operator the following way
#include <iostream>
#include <string>
std::ostream & operator<<(std::ostream & os, const char *s)
{
return std::operator <<( os, s ) << '\n';
}
int main()
{
std::cout << "stackoverflow";
std::cout << "stackoverflow";
}
and get the expected result
stackoverflow
stackoverflow
Note that "stackoverflow" is of type const char[], but not std::string. That means your overload won't be invoked, but the one from standard library (operator<<(std::basic_ostream) is invoked, because it's an exact match and doesn't require the implicit conversion from const char[] to std::string.
template< class Traits >
basic_ostream<char,Traits>& operator<<( basic_ostream<char,Traits>& os,
const char* s );
BTW: It could be found because of ADL.
You can overload globally, but "stackoverflow" is not a std::string, so yours isn't used.
(And there already is such an overload in the standard library.)
To see that it works, move your first overload out of the class definition and make it a non-friend.
The only reason it has to be declared friend is that you have declared it inside the class definition, so it would be a member function otherwise.
This will work as you expect:
struct Test
{
std::string d_data;
Test(const std::string & data) : d_data{data} {}
};
std::ostream & operator<<(std::ostream & ostr, const Test & obj)
{
ostr << obj.d_data << '\n';
return ostr;
}
int main()
{
Test t1("one");
std::cout << t1;
Test t2("two");
std::cout << t2;
}
I'm trying to make a C++ class resembling std::ostream, that will take its input and write to two std::ostreams given in the constructor. Here it is together with appropriate operator<< template:
struct SplitStream
{
SplitStream(std::ostream & a_, std::ostream & b_) : a(a_), b(b_) {}
std::ostream & a, & b;
};
template<class T>
const SplitStream & operator << (const SplitStream & sp, const T & x)
{
sp.a << x;
sp.b << x;
return sp;
}
Several lines below that code, I try to use this class:
void foo(SplitStream & out)
{
double some_double = 1.23;
out << "bar" << some_double << std::endl;
}
And I get this rather enigmatic error:
... error C2678: binary '<<' : no operator found which takes a left-hand operand of type 'const SplitStream' (or there is no acceptable conversion) ...
What am I doing wrong? I tried to define operator<< without consts, and it didn't compile either.
The immediate problem is that std::endl isn't an object but a function template declared something like this:
template <typename cT, typename Traits>
std::basic_ostream<cT, Traits>& endl(std::basic_ostream<cT, Traits>&);
To use a function pointer like this, the template arguments need to be deduced. To this end, the class std::basic_ostream<cT, Traits> declared suitable overloads for operator<<():
template <typename cT, typename Traits>
std::basic_ostream<cT, Traits>& std::baisic_ostream<cT, Traits>::operator<< (
std::basic_ostream<cT, Traits>& (*manip)(std::basic_ostream<cT, Traits>&));
This way, the compiler can deduce the correct instantiation when the std::endl function is referenced.
However, all that is utterly irrelevant because what you are trying to do is better done entirely differently! You should create a suitable stream buffer and use a reasonably constructed std::ostream with this custom stream buffer. Below is a complete example how to do it properly (I had posted it before but only a couple dozens times...):
#include <streambuf>
struct teebuf
: std::streambuf
{
std::streambuf* sb1_;
std::streambuf* sb2_;
teebuf(std::streambuf* sb1, std::streambuf* sb2)
: sb1_(sb1), sb2_(sb2) {
}
int overflow(int c) {
typedef std::streambuf::traits_type traits;
bool rc(true);
if (!traits::eq_int_type(traits::eof(), c)) {
traits::eq_int_type(this->sb1_->sputc(c), traits::eof())
&& (rc = false);
traits::eq_int_type(this->sb2_->sputc(c), traits::eof())
&& (rc = false);
}
return rc? traits::not_eof(c): traits::eof();
}
int sync() {
bool rc(true);
this->sb1_->pubsync() != -1 || (rc = false);
this->sb2_->pubsync() != -1 || (rc = false);
return rc? 0: -1;
}
};
#include <fstream>
#include <iostream>
int main()
{
std::ofstream fout("tee.txt");
teebuf sbuf(fout.rdbuf(), std::cout.rdbuf());
std::ostream out(&sbuf);
out << "hello, world!\n";
}
The other answer is better, but for completeness:
The SplitStream references in your operator<< should not be const, since they are modifying the streams that the struct contains.
template<class T>
SplitStream & operator << (SplitStream & sp, const T & x)
{
sp.a << x;
sp.b << x;
return sp;
}
EDIT: Passed Expression exp and string expression by const reference
I'm trying to allow a class to be display via cout in the following manner:
#include <iostream>
class Expression {
private:
std::string expression;
public:
Expression(const std::string& expression):
expression(expression) { }
friend std::ostream& operator <<(ostream& os, const Expression& exp) {
return os << exp.expression; }
};
however, on compiling I get the errors:
main.cpp(9) : error C2061: syntax error : identifier 'ostream'
main.cpp(9) : error C2809: 'operator <<' has no formal parameters
this is especially confusing because VC++ is giving me ostream as an autocompletion suggestion when I enter std::. What's causing these errors, and how can they be resolved?
Surely you need std::ostream in all locations? i.e.:
friend std::ostream& operator <<(std::ostream& os, Expression& exp) ...
^^^
Without a using namespace std; clause (which has its own set of problems), you need to fully qualify all the iostream stuff.
You can see this with the following program:
#include <iostream>
class Expression {
private:
std::string expression;
public:
Expression(std::string expression):
expression(expression) { }
// added this bit.
// _/_
// / \
friend std::ostream& operator <<(std::ostream& os, Expression& exp) {
return os << exp.expression; }
};
int main (void) {
Expression e ("Hi, I'm Pax.");
std::cout << e << std::endl;
return 0;
}
which prints out:
Hi, I'm Pax.
as expected.
And, as some comments have pointed out, you should pass the string as const-reference:
#include <iostream>
class Expression {
private:
std::string expression;
public:
Expression(const std::string& expression)
: expression(expression) {
}
friend std::ostream& operator <<(std::ostream& os, const Expression& exp) {
return os << exp.expression;
}
};
int main (void) {
Expression e ("Hi, I'm Pax.");
std::cout << e << std::endl;
return 0;
}
The following won't compile for me. I'm out of ideas... Any help?
template<>
inline
std::ostream& operator<< <const std::map<std::string, std::string> > (std::ostream& stream, const std::map<std::string, std::string>& some_map)
{
return stream;
}
g++ gives me the following error:
error: expected initializer before '<' token
Edit: 1
Okay, since everyone is telling me to overload, let me give you an example that wouldn't make sense for overloading. What if I have this:
template <typename T>
inline
std::ostream& operator<<(std::ostream& stream, const T& something)
{
stream << something.toString();
return stream;
}
class Foo
{
public:
Foo(std::string s)
{
name = s;
}
std::string toString() const
{
return name;
}
private:
std::string name;
};
class Bar
{
public:
Bar(int i)
{
val = i;
}
std::string toString() const
{
std::ostringstream stream;
stream << val;
return stream.str();
}
private:
int val;
};
int main(int, char**)
{
Foo foo("hey");
Bar bar(2);
std::cout << foo << std::endl;
std::cout << bar << std::endl;
return 0;
}
Now this won't work either.
I just want to avoid having to overload operator<< over and over by using a template like above. This seems like it should be possible. I would like to know if it is, and if so, how?
In such a scenario, overloading for both Foo and Bar to do the same thing would be a waste, that is why I am trying to avoid it.
Edit: 2
Okay, it appears that I am being misunderstood. Here is another attempt to clarify:
template <typename T>
std::ostream& operator<<(ostream& stream, const T& t)
{
for(typename T::const_iterator i = t.begin(), end = t.end(); i != end; ++i)
{
stream << *i;
}
return stream;
}
int main(int, char**)
{
set<int> foo;
list<string> bar;
vector<double> baz;
cout << foo << " " bar << " " << baz << endl;
};
The above code won't work mind you. Complains about ambiguity. But it seems like the better solution for printing out containers. If I did it the with overloading, I would need to write a version of operator<< for each container/datatype combination, which would yield a ridiculous amount of code duplication.
This doesn't need to be a template function.
std::ostream & operator<<(std::ostream & stream, const std::map<std::string, std::string> & some_map)
{
return stream;
}
Edit:
In reference to my comment about writing Java in C++(and sorry if it sounded rude, I didn't intend to be smarmy). Tell me if this doesn't work better for you. Instead of writing a "toString" method in the first place, just overload the operator<< to begin with. The function is nearly identical. Then, you can write a non-member template toString function that will automatically work with all of your classes, like this:
#include <sstream>
#include <string>
template<typename T>
std::string toString(const T & val)
{
std::ostringstream ostr;
ostr << val;
return ostr.str();
}
Edit 2
Here's my alternative if you still insist on doing it your way. Make all of your classes with the toString method inherit from an abstract class with a virtual toString method, then write one operator<< to handle all of them.
class Stringifiable
{
public:
virtual std::string toString() const = 0;
};
std::ostream & operator<<(std::ostream & ostr, const Stringifiable& something)
{
return ostr << something.toString();
}
Now the compiler will choose your overload over templates.
You can use SFINAE to remove the template overload from consideration. Note that this has to be a part of the signature of the function. Thus you can use boost::enable_if:
template < typename T >
typename boost::enable_if< meta_function_to_check_for_concept<T>, std::ostream&>::type
operator << (std::ostream & out, T const& t)
{
...
}
If you don't do this then your template will attempt to match almost anything and will explode for every use of << that is not in line with the concept you're trying to match.
Your example is a bit contrived and might not lend itself to this answer, but there are situations in which it's warranted. This is how to do it.
In Crazy Eddie's answer, he mentions SFINAE. Now, C++11 has that built in. If all types derive from the same base class, this is made pretty simple. Here's a more complete example using C++11:
#include <type_traits>
#include <iostream>
#include <ostream>
class MyBaseType {};
class MyClass : MyBaseType {};
class MyOtherClass : MyBaseType {};
class SomeType {};
template <typename T>
typename std::enable_if<std::is_base_of<MyBaseType,T>::value,std::ostream&>::type
operator<<(std::ostream& out, const T& x)
{
out << 1;
}
int main()
{
MyBaseType x;
MyClass y;
MyOtherClass z;
SomeType i;
std::cout << x << y << z; // success!
std::cout << i; // compile-time failure!
}
Just as the title asks, does C++ have the equivalent of Python's setitem and getitem for classes?
Basically it allows you to do something like the following.
MyClass anObject;
anObject[0] = 1;
anObject[1] = "foo";
basically, you overload the subscript operator (operator[]), and it returns a reference (so it can be read as well as written to)
You can overload the [] operator, but it's not quite the same as a separate getitem/setitem method pair, in that you don't get to specify different handling for getting and setting.
But you can get close by returning a temporary object that overrides the assignment operator.
To expand on Earwicker post:
#include <string>
#include <iostream>
template <typename Type>
class Vector
{
public:
template <typename Element>
class ReferenceWrapper
{
public:
explicit ReferenceWrapper(Element& elem)
: elem_(elem)
{
}
// Similar to Python's __getitem__.
operator const Type&() const
{
return elem_;
}
// Similar to Python's __setitem__.
ReferenceWrapper& operator=(const Type& rhs)
{
elem_ = rhs;
return *this;
}
// Helper when Type is defined in another namespace.
friend std::ostream& operator<<(std::ostream& os, const ReferenceWrapper& rhs)
{
return os << rhs.operator const Type&();
}
private:
Element& elem_;
};
explicit Vector(size_t sz)
: vec_(sz)
{
}
ReferenceWrapper<const Type> operator[](size_t ix) const
{
return ReferenceWrapper<const Type>(vec_[ix]);
}
ReferenceWrapper<Type> operator[](size_t ix)
{
return ReferenceWrapper<Type>(vec_[ix]);
}
private:
std::vector<Type> vec_;
};
int main()
{
Vector<std::string> v(10);
std::cout << v[5] << "\n";
v[5] = "42";
std::cout << v[5] << "\n";
}
It's not portable, but MSVC has __declspec(property), which also allows indexers:
struct Foo
{
void SetFoo(int index, int value) { ... }
int GetFoo(int index) { ... }
__declspec(property(propget=GetFoo, propput=SetFoo)) int Foo[];
}
other than that, Earwicker did outline the portable solution, but he's right that you'll run into many problems.