I would like to use std::stringstream to create formatted strings, but use the class inline so I don't have stringstream local variables flying around. What I mean is this:
#include <iostream>
#include <ostream>
#include <string>
#include <sstream>
int main(int argc, char* argv[])
{
std::string test = ((std::ostringstream&)
(std::ostringstream("") << "This is a test: " << 50.1 << "abc")
).str();
std::cout << test << std::endl;
return 0;
}
This compiles fine in GCC, however the output is the following:
"0x401d0a50.1abc"
So it seems that stringstream treats the first string as a pointer and outputs the address. Subsequent operator<<'s work fine.
How do I fix this?
Thanks!
The reason is that the << operator is a member for void const*, but a free function taking an std::ostream& as the left hand argument for char const*. Your std::ostringstream( "" ) is a temporary: you can call member functions (even non-const member functions) on it, but a temporary cannot be used to initialize the non-const reference of the global function.
EDIT:
Two points: first, as has been pointed out, g++ does do what you
want if you specify -std=c++11. As T.C. points out, this is
specified in §27.7.3.9, which provides a template overload for
all << with an rvalue reference for the std::istream
parameter.
And second, the classic work around is
to start the expression std::ostringstream( "" ).flush() <<.... flush is a member function (and so can be called on
a temporary) which returns an std::ostream& (so everything
else chains nicely); it also does nothing on
a std::ostringstream.
Found it. The C++11 standard special-cases rvalue streams with an extra template operator<< overload. §27.7.3.9 of the standard:
Rvalue stream insertion [ostream.rvalue]
template <class charT, class traits, class T>
basic_ostream<charT, traits>&
operator<<(basic_ostream<charT, traits>&& os, const T& x);
Effects: os << x
Returns: os
It's obviously a better match than the member operator<< that takes a const void * and hence is selected by overload resolution in C++11 mode. In C++98 mode this overload doesn't exist (since there are no rvalue references) and the only viable overload is the member operator<< (since, as James Kanze explains in his answer, the temporary can't bind to the non-const lvalue reference in the free operator<< overload that takes a const char *).
Related
I was trying to add some debug output into a C++03 project and got some strange result. Here's the simplified test code:
#include <fstream>
int main()
{
{
std::ofstream file("/tmp/test.txt");
file << "hello" << " ... OK, this works\n";
}
std::ofstream("/tmp/test.txt",std::ios_base::app) << "hello"
<< " ... no, I mean hello!\n";
}
For some reason, here's what I get after compilation:
$ g++ test.cpp -o test && ./test && cat /tmp/test.txt
hello ... OK, this works
0x80487fe ... no, I mean hello!
Why do I get a hex number in the case of outputting a string to unnamed std::ofstream object? And why does the subsequent output of a second string work?
The usual operator<< which we use for passing C strings to std::ostream is declared as a free function
template< class Traits >
basic_ostream<char,Traits>& operator<<( basic_ostream<char,Traits>& os,
const char* s );
The unnamed std::ofstream object is a temporary variable, and temporaries can't bind to a nonconst reference, thus this operator overload doesn't participate in overload resolution. Instead, the closest match is taken, a member function
std::basic_ostream& std::basic_ostream::operator<<(const void*);
, which takes a type-erased pointer and just prints its value. Since member functions can be called with the object being a temporary, this one does work out. This explains the hex number in output. Now, this operator returns a reference, std::basic_ostream&. As this is no longer a temporary object and is instead a reference to some nonconst object, the usual free-function overload of operator<<, which takes const char*, can be successfully called. This is why the second string is printed as expected.
Note that since C++11 the code will work as expected, since there we have an additional overload of operator<<, which takes an rvalue reference:
template< class CharT, class Traits, class T >
basic_ostream< CharT, Traits >& operator<<( basic_ostream<CharT,Traits>&& os,
const T& value );
, and the temporary does bind to rvalue reference.
To make the code work in C++03, you can use a member function std::ostream::flush(), which returns a nonconst reference to the object and doesn't have any user-visible side effects on the fstream object:
#include <fstream>
int main()
{
std::ofstream("/tmp/test.txt").flush() << "hello"
<< " ... OK, this now works too\n";
}
Potentially related articles:
Overload resolution between object, rvalue reference, const reference
std::begin and R-values
For a STL container C, std::begin(C) and similar access functions including std::data(C) (since C++17) are supposed to have the same behavior of C::begin() and the other corresponding C's methods. However, I am observing some interesting behaviors due to the details of overload resolution involving lvalue/rvalue references and constness.
DataType1 is int* as easily expected. Also, confirmed the by with Boost's type_id_with_cvr. const vector<int> gives int const* No surprise here.
using T = vector<int>;
using DataType1 = decltype(T().data()); // int*
using CT = const T;
using DataType2 = decltype(CT().data()); // int const*
using boost::typeindex::type_id_with_cvr;
cout << type_id_with_cvr<DataType1>() << endl; // prints int*
...
I tried std::data, which can also handle arrays and non-STL containers. But it yields int const*. Similarly, std::begin returns a const iterator, even though T is not const.
using T = vector<int>;
using DataType3 = decltype(std::data(T())); // int const* Why ???
using CT = const T;
using DataType4 = decltype(std::data(CT())); // int const*
Question: What is the reason of this difference? I expected that C.data() and std::data(C) would behave in the same manner.
Some my research: In order to get int* for DataType3, T must be converted to non-const lvalue reference type explicitly. I tried declval, and it was working.
using DataType3 = decltype(std::data(std::declval<T&>())); // int*
std::data provides two overloads:
template <class _Cont> constexpr
auto data(_Cont& __c) -> decltype(__c.data()) { return __c.data(); }
// non-const rvalue reference argument matches to this version.
template <class _Cont> constexpr
auto data(const _Cont& __c) -> decltype(__c.data()) { return __c.data(); }
While resolving overloaded functions for std::data, T(), which is non-const rvalue reference, is matched to the const T& version instead of T& version.
It was not easy to find this specific overload resolution rule in the standard (13.3, over.match). It'd be much clearer if someone could point the exact rules for this issue.
This behaviour is attributed to overload resolution rules. As per standard 8.5.3/p5.2 References [dcl.init.ref], rvalue references bind to const lvalue references. In this example:
std::data(T())
You provide to std::data an rvalue. Thus, due to overload resolution rules the overload:
template <class _Cont> constexpr
auto data(const _Cont& __c) -> decltype(__c.data()) { return __c.data(); }
is a better match. Consequently you get const int*
You can't bind a temporary to a non-const lvalue reference.
The only line that is mildly surprising is using DataType1 = decltype(T().data()); // int*.
...but it is still normal, member functions can be called on temporary objects without being treated as const. This is another non trivial difference between member functions and free functions.
For example, in C++98 (pre-rvalue refs) it was not possible to do std::ofstream("file.txt") << std::string("text") because operator<< is not member and the temporary is treated as const. If operator<< were a member of std::ofstream it would be possible (and may even make sense). (The situation changed later in C++11 with rvalue references but the point is still valid).
Here it is an example:
#include<iostream>
struct A{
void f() const{std::cout << "const member" << std::endl;}
void f(){std::cout << "non const member" << std::endl;}
};
void f(A const&){std::cout << "const function" << std::endl;}
void f(A&){std::cout << "non const function" << std::endl;}
int main(){
A().f(); // prints "non const member"
f(A()); // prints "const function"
}
The behavior is exposed when the object is temporarily constructed and used. In all other cases I can imagine, member f is equivalent to f free function.
(r-value reference qualifications && --for member and function-- can give you a more fine grained control but it was not part of the question.)
I'm playing around with variadic templates, and wrote this, based on this answer :
template <size_t... I>
void print(seq<I...>)
{
decltype(std::cout) * dummy[sizeof...(I)] = { &(std::cout << I << ' ')... };
}
Because std::cout::operator<< has a return type, it can be stored, so there's no need for the ( ,0) comma trick.
Now, to shut up the "unused variable 'dummy'" warning, and to print a newline, I tried the following statements, but they didn't do what I wanted:
dummy[0]->operator <<('\n'); // prints 10
(apparently called operator<<(int) instead of operator<<(char)
dummy[0]->operator <<("\n"); // prints a pointer
(apparently called operator<<(const void*) instead of operator<<(const char*)
In the end, I had to write
*dummy[0] << '\n'; // prints a newline as desired
My question is, why did the "wrong" overloads get chosen?
The "wrong" overloads are chosen because only some overloads are members of std::ostream class. The overloads for char and const char* are not members of std::ostream, but free functions, so, in
*dummy[0] << '\n';
argument-dependent lookup will find operator<<(std::ostream&, char), but in
dummy[0]->operator <<('\n');
only member functions will be considered, resulting in std::ostream::operator<<(int) being called.
As far as I understand C++11 references, I should not be able to bind an rvalue reference to a (non-const) lvalue reference as the former might be bound to a temporary and the latter must never be bound to a temporary.
However I found this odd behaviour in conjunction temporary stream objects (which I reduced as far as I could)
struct Dummy {};
template <typename Stream>
Stream& operator<<(Stream& s, Dummy) {
return s << "."; // <- (A)
}
template <typename Stream>
void pass(Stream&& s) {
std::move(s) << Dummy(); // <- (X) rvalue->lvalue conversion?
}
#include <fstream>
int main() {
pass(std::fstream("test",std::ios::out));
}
If I write s << Dummy() in line (X), C++ complains in line (A), saying
error: invalid initialization of reference of type ‘std::basic_fstream<char>&’ from expression of type ‘std::basic_ostream<char>’
However, why does the code (as shown above) compiles and works as expected? The rvalue reference returned by std::move should just be as unable to being bound to an lvalue reference as the expression s is, but both gcc 4.6.1 and gcc 4.7.2 react identically.
And why does this phenomenon only appear to work with streams? When directly passing a Dummy&& to a function that expects a T& fails both with and without std::move.
basic_ostream has an overload of operator<< that looks like this:
template <typename Elem, typename Traits, typename T>
basic_ostream<Elem, Traits>&
operator<<(basic_ostream<Elem, Traits>&& sink, const T& val)
{
return sink << val;
}
This is called "Rvalue stream insertion" in the standard, at §27.7.3.9 [ostream.rvalue].
It allows implicit conversion (of sorts) from an rvalue basic_ostream to an lvalue. It was introduced specifically to allow temporary streams to be usable without resorting to tricks.
As for why the compile fails when you omit the move:
When Stream& operator<<(Stream& s, Dummy) is called without the move, Stream will be std::fstream which inherits from std::ostream (i.e. basic_ostream<char>).
It will use the basic_ostream<E, T>& operator<<(basic_ostream<E, T>&, const char*) overload to insert your string, then try to return the result of that expression which will be an ostream. You cannot implicitly downcast from std::ostream& to std::fstream&, so you get an error.
You can fix this by returning s on it's own line (where it won't have been implicitly upcasted.)
This isn't a problem with move because you go through that rvalue-to-lvalue insertion operator we just discovered first. Inside that function, the stream is a basic_ostream and so Stream is as well, and the return types will match.
The following code is giving me a compilation error. Can anyone please tell me why?
class mytype {
public:
int value;
mytype(int a) {
value = a;
}
friend ostream& operator<<(ostream& stream, const mytype& a) {
stream << a.value;//works
return stream;
}
friend ostringstream& operator<<(ostringstream& stream, const mytype& a) {
stream << (a.value);//compilation error
return stream;
}
};
Error:
error C2027: use of undefined type
'std::basic_ostringstream<_Elem,_Traits,_Alloc>'
Upon fixing that:
error C2666: 'operator <<' : 18 overloads have similar conversions
Final fix:
Declare constructor as explicit. Works on MSVC then.
I wonder why.
error C2027: use of undefined type 'std::basic_ostringstream<_Elem,_Traits,_Alloc>'
You need #include <sstream> to get the [i/o]stringstream classes.
About the other errors
The problem with an overload of the form
ostringstream& operator<<(ostringstream& stream, const mytype& a)
is that it matches an ostringstream exactly. Why is it a bad thing to have a more exact overload? From the standard, §13.3.3/1-2:
a viable function F1 is defined to be a better function than another viable function F2 if for all arguments i, ICSi(F1) is not a worse conversion sequence than ICSi(F2) …
If there is exactly one viable function that is a better function than all other viable functions, then it is the
one selected by overload resolution; otherwise the call is ill-formed
Therefore if operator<<( ostream &, int ) and operator<<( ostringstream &, mytype const & ) are both candidates for stream << value, the former matches int exactly with no conversion but the latter matches ostringstream exactly. Therefore neither can be "not worse" for all arguments, and neither candidate may be chosen.
But the code is valid because of a loophole. Your overload is not a candidate at all, except when you actually use your type in the function call. When you declare/define a friend inside a class block, it does not introduce it to any namespace scope; it merely associates it with the class scope, which allows it to be found if that class type describes one of the arguments being passed.
The standard has this to say about friend declarations, although it's in another section (14.6.5):
Friend declarations do not introduce new names into any scope…
So, MSVC tried to be nice and proactively introduced your friend to its enclosing namespace. Strike against MSVC.
However, when I attempted to add a declaration equivalent to what MSVC did "for free," Comeau and GCC nicely resolved the resulting overloading conflict — strike against them. Or is it? As it turns out, the overloaded call occurs earlier in the file than my recommended declaration. If I move the declaration before class mytype { (which requires forward-declaring mytype), then both properly complain about the ambiguity.
Using an overload before it is declared in namespace scope appears to be well and good according to §3.3-3.4 of the Standard. So actually GCC and Comeau were both in the right. The point of declaration is right after the name of the declared object. (And last I checked, self-referential function declarations can still crash GCC.) ADL invokes unqualified lookup into the enclosing namespace at a point immediately before the enclosing class. (3.4.1/8 final bullet, 3.4.1/9, 3.4.2/2a.) If the friend hasn't been declared before the class, it's legitimately not a candidate. (7.3.1.2/3) Isn't C++ a beautiful language?
How keep the simplified example on GCC, but break subsequent code.
friend ostringstream& operator<<(ostringstream& stream, const mytype& a) {
stream << (a.value);//compilation error
return stream;
}
};
ostringstream& operator<<(ostringstream& stream, const mytype& a); // <- here
Following this declaration, it will be impossible to write an int into an ostringstream.
How to break everything uniformly, with simpler declaration semantics.
class mytype; // <- here
// and here:
inline ostringstream& operator<<(ostringstream& stream, const mytype& a);
class mytype {
public:
Following this declaration, it will be impossible to write an int into an ostringstream… including the friend declarations inside class mytype {}.
Actual solution.
The stream classes are supposed to be indistinguishable. If you really want to determine whether a given stream feeds a string in memory (and you shouldn't), it's best to look at its internal streambuf object, returned by rdbuf(), which actually performs the I/O gruntwork. Even a generic ostream object can have ostringstream functionality if given a stringbuf.
if ( typeid( stream.rdbuf() ) == typeid( stringbuf * ) ) {
// this is effectively a stringstream
} else {
// not a stringstream
}
There is an overload ambiguity in the call to operator<< in the ostringstream overload.
stream << a.value;
There are a number of operator<< overloads that are members of the ostream class, which is a base class of ostringstream. One of these is declared as:
ostream& ostream::operator<<(int);
This overload is an exact match for the right-hand side (a.value is an int) but requires a derived-to-base conversion on the left-hand side (stream is an ostringstream, which is derived from ostream).
However, there is also your ostringstream overload:
ostringstream& operator<<(ostringstream&, const mytype&);
This overload is an exact match for the left-hand side (stream is an ostringstream), and a user-defined converting constructor (your mytype(int) constructor) can be used to convert a.value (an int) to a mytype.
Since one overload matches the first argument better and the other overload matches the second argument better, there is an ambiguity. You can fix this either by:
Explicitly converting the left-hand side to an ostream (using (ostream&)stream = a.value;), or
Remove the user-defined conversion by making the constructor explicit.