Adding streaming operators to std::string, your opinion?

F

Francesco

Hi there,
take a look to this snippet:
-------
#include <iostream>
#include <sstream>

std::string& operator<<(std::string& s, int i) {
std::eek:stringstream stream;
stream << i;
return s += stream.str();
}

int main() {
std::string s = "Eleven == ";
int i = 11;
s << i;
std::cout << s << std::endl;
return 0;
}
-------

The topic about printing integers into a string raised this thought of
mine: is it "good" to add streaming operations to regular strings?

I could have posted it into that thread, but I didn't want to hijack
it, I'm just looking for some opinion about such kind of extensions,
out of curiosity.

My point of view is that it shouldn't be a problem. Of course, the
operator<<() posted above would be better being a template to accept
more types at once, and would be fine when you can get along with the
default stream formatting - just my opinion, I'll be glad to read
yours.

Thanks for reading,
Francesco
 
R

Rune Allnor

The topic about printing integers into a string raised this thought of
mine: is it "good" to add streaming operations to regular strings? ....
My point of view is that it shouldn't be a problem. Of course, the
operator<<() posted above would be better being a template

First of all, template classes can not rely on
already linked code, so once you 'go template,'
*all* the functionality of the function or class
would have to be expressed in terms of template code.

One problem you would face is that file streams are
tightly couplede to the OS and HW system. Such details
are taken care of in system-specific compiled libraries.
You would likely have to move all of that into 'template
domain' for your idea to work.

Rune
 
F

Francesco

First of all, template classes can not rely on
already linked code, so once you 'go template,'
*all* the functionality of the function or class
would have to be expressed in terms of template code.

One problem you would face is that file streams are
tightly couplede to the OS and HW system. Such details
are taken care of in system-specific compiled libraries.
You would likely have to move all of that into 'template
domain' for your idea to work.

Hi Rune, thanks for dropping in.

I'm not sure I understand your points, surely this is due to the fact
that I expressed myself badly in the original post and I'm confronting
your points to my idea, which wasn't clear from the start.

I meant creating a local template to be used as a helper function to
build strings "on the fly" as proposed else-thread here on clc++ by
other posters, something like this:

-------
#include <iostream>
#include <sstream>

template<class T>
std::string& operator<<(std::string& s, T t) {
std::eek:stringstream stream;
stream << t;
return s += stream.str();
}

int main() {
std::string s;
std::string s78 = "78";
s << "int: " << 78 << ", "
<< "float: " << 7.8 << ", "
<< "chars: " << '\67' << '\70' << ", "
<< "string: " << s78;
std::cout << "s == \"" << s << "\"" << std::endl;
std::cout << "s78 == \"" << s78 << "\"" << std::endl;
return 0;
}
-------

I've noticed that my operator<<() template gets called only when the
leftmost object in a sequence of insertions is a string, hence strings
can be safely used when outputting to ostreams as I've done above,
also, strings can be inserted into other strings in the same way -
yes, I've had to try it to be sure ;-)

Well, just playin' along, nothing serious.

Cheers,
Francesco
 
J

Jerry Coffin

[ ... ]
The topic about printing integers into a string raised this thought
of mine: is it "good" to add streaming operations to regular
strings?

Not really -- you're combining two entirely separate kinds of
responsibility: formatting and storage. A string is basically a way
of storing something. If you want to format, there's already the
iostreams classes for doing that. If you want to format something
with an ostream, and store the result in a string, that would be an
ostringstream.
 
A

Alf P. Steinbach

* Jerry Coffin:
[ ... ]
The topic about printing integers into a string raised this thought
of mine: is it "good" to add streaming operations to regular
strings?

Not really -- you're combining two entirely separate kinds of
responsibility: formatting and storage. A string is basically a way
of storing something. If you want to format, there's already the
iostreams classes for doing that. If you want to format something
with an ostream, and store the result in a string, that would be an
ostringstream.

It depends what the << is used for.

When it's used for concatenation it can be much more efficient and much more
clear and readable than some non-operator approach.

E.g. writing

void bar()
{
foo( S() << n << " items processed, " << nBadItems << " bad 'uns" );
}

instead of

void bar()
{
foo(
toString( n ) +
" items processed " +
toString( nBadItems ) +
" bad 'uns"
);
}

where one should note that for a typical implementation of string concatenation
'+' operator the latter is less clear and to boot is generally quadratic time,
O(e^2), in the number of string elements e to be concatenated -- while the
former is O(e) for any reasonable string implementation (in place modification).

So, provided it's done for a good reason, and done correctly, using << to
concatenate strings can be a very good idea.


Cheers & hth.,

- Alf
 
F

Francesco

Francesco, (e-mail address removed) says...
[snip]
[snip]

When it's used for concatenation it can be much more efficient and much more
clear and readable than some non-operator approach.
[snip]

where one should note that for a typical implementation of string concatenation
'+' operator the latter is less clear and to boot is generally quadratic time,
O(e^2), in the number of string elements e to be concatenated -- while the
former is O(e) for any reasonable string implementation (in place modification).

So, provided it's done for a good reason, and done correctly, using << to
concatenate strings can be a very good idea.

First of all, thanks everybody for your posts.
Every point of view is interesting, sorry if I'm not replying
individually to everyone.

@ Alf: please let me understand your point.

I've tried to implement and profile at once all three possibilities
(inserters, toString function with the default + operator, direct
stringstream usage). To be fair between the measurements, I've helped
the "inserters" version as much as possible (since the toString needs
to be called fewer times).

It turns out that the two versions get more or less equal timings - in
my implementation, of course.

I suppose you were speaking about an ad-hoc string class that includes
inserters from the beginning, but then that would be something like an
ostringstream, while my idea was just to add some local helper
function to stream into a std::string for simpler-notation's sake.

What am I missing about the quadratic difference you spoke about?

Here is my code...
-------
#include <iostream>
#include <sstream>
//#include "profiler.h"

using namespace std;

template<class T>
inline string& operator<<(string& s, const T& t) {
ostringstream stream;
stream << t;
return s += stream.str();
}

inline string& operator<<(string& s, const string& s2) {
return s += s2;
}

inline string& operator<<(string& s, const char* cstr) {
return s += cstr;
}

inline string& operator<<(string& s, char ch) {
return s += ch;
}

template<class T> inline string toString(const T& t) {
ostringstream stream;
stream << t;
return stream.str();
}

const string str = "string";

string UseInserter() {
// profiler::profiler p("UseInserter()");
string s;
s << "Int: " << 42
<< ", bool: " << false
<< ", float: " << 4.2
<< ", string: " << str
<< ", char: " << '_';
return s;
}

string UseToString() {
// profiler::profiler p("UseToString()");
string s = "Int: " + toString(42)
+ ", bool: " + toString(false)
+ ", float: " + toString(4.2)
+ ", string: " + str
+ ", char: " + '_';
return s;
}

string UseSStream() {
// profiler::profiler p("UseSStream()");
ostringstream ss;
ss << "Int: " << 42
<< ", bool: " << false
<< ", float: " << 4.2
<< ", string: " << str
<< ", char: " << '_';
return ss.str();
}

int main() {
for (int i = 0; i < 1000001; ++i) {
UseInserter();
UseToString();
UseSStream();
}
// profiler::report(cout);
return 0;
}
-------

(I used my homemade profiler as posted else-thread here on clc++, I
commented out its use to ease using professional tools on your side)

....and here is its output:

-------
Id: UseInserter()
Avg time: 0.016252 msecs
Total time: 16252 msecs
Calls count: 1000001

Id: UseSStream()
Avg time: 0.00664999 msecs
Total time: 6650 msecs
Calls count: 1000001

Id: UseToString()
Avg time: 0.016495 msecs
Total time: 16495 msecs
Calls count: 1000001
 
A

Alf P. Steinbach

* Francesco:
Francesco, (e-mail address removed) says...
[snip]
The topic about printing integers into a string raised this thought
of mine: is it "good" to add streaming operations to regular
strings?
[snip]

When it's used for concatenation it can be much more efficient and much more
clear and readable than some non-operator approach.
[snip]

where one should note that for a typical implementation of string concatenation
'+' operator the latter is less clear and to boot is generally quadratic time,
O(e^2), in the number of string elements e to be concatenated -- while the
former is O(e) for any reasonable string implementation (in place modification).

So, provided it's done for a good reason, and done correctly, using << to
concatenate strings can be a very good idea.

First of all, thanks everybody for your posts.
Every point of view is interesting, sorry if I'm not replying
individually to everyone.

@ Alf: please let me understand your point.

I've tried to implement and profile at once all three possibilities
(inserters, toString function with the default + operator, direct
stringstream usage). To be fair between the measurements, I've helped
the "inserters" version as much as possible (since the toString needs
to be called fewer times).

Well, you haven't (see below).

But it doesn't matter here.

It turns out that the two versions get more or less equal timings - in
my implementation, of course.

Not at all. Your timings show the inserters to be superior. And among the two
inserter approaches, which are fastest, the one that doesn't do a lot of extra
needless work per insertion, is -- not unexpectedly! -- slightly faster.

I suppose you were speaking about an ad-hoc string class that includes
inserters from the beginning, but then that would be something like an
ostringstream,

It would, yes. :)

while my idea was just to add some local helper
function to stream into a std::string for simpler-notation's sake.

Generally that's a good idea, but invoking std::eek:stringstream in each << and
then for each such result extracting a string and copying it plus a
concatenation, is ungood for efficiency because, as Jerry remarked else-thread
or was it up-thread, you're then doing much extra, needless work.

Instead do something like (off the cuff)

class S
{
private:
std::eek:stringstream myStream;

public:
S() {}
S( char const s[] ): myStream( s ) {}
S( std::string const& s ): myStream( s ) {}

template< typename T >
S& operator<<( T const& v )
{
myStream << v;
return *this;
}

std::string str() const { return myStream.str(); }
operator std::string () const { return myStream.str(); }
};

What am I missing about the quadratic difference you spoke about?

You haven't tested it. Your timings are dominated by the inefficient conversion
from number to string, and you have very short strings and low number of them,
avoiding all three factors that might make that difference count. It's possible
that you'll see it if you use e.g. sprintf to implement the conversion, and/or
if you use longer strings, and/or if you have more of them.

Here is my code...
-------
#include <iostream>
#include <sstream>
//#include "profiler.h"

using namespace std;

template<class T>
inline string& operator<<(string& s, const T& t) {
ostringstream stream;
stream << t;
return s += stream.str();
}

inline string& operator<<(string& s, const string& s2) {
return s += s2;
}

inline string& operator<<(string& s, const char* cstr) {
return s += cstr;
}

inline string& operator<<(string& s, char ch) {
return s += ch;
}

template<class T> inline string toString(const T& t) {
ostringstream stream;
stream << t;
return stream.str();
}

const string str = "string";

string UseInserter() {
// profiler::profiler p("UseInserter()");
string s;
s << "Int: " << 42
<< ", bool: " << false
<< ", float: " << 4.2
<< ", string: " << str
<< ", char: " << '_';
return s;
}

string UseToString() {
// profiler::profiler p("UseToString()");
string s = "Int: " + toString(42)
+ ", bool: " + toString(false)
+ ", float: " + toString(4.2)
+ ", string: " + str
+ ", char: " + '_';
return s;
}

string UseSStream() {
// profiler::profiler p("UseSStream()");
ostringstream ss;
ss << "Int: " << 42
<< ", bool: " << false
<< ", float: " << 4.2
<< ", string: " << str
<< ", char: " << '_';
return ss.str();
}

int main() {
for (int i = 0; i < 1000001; ++i) {
UseInserter();
UseToString();
UseSStream();
}
// profiler::report(cout);
return 0;
}
-------

(I used my homemade profiler as posted else-thread here on clc++, I
commented out its use to ease using professional tools on your side)

...and here is its output:

-------
Id: UseInserter()
Avg time: 0.016252 msecs
Total time: 16252 msecs
Calls count: 1000001

Id: UseSStream()
Avg time: 0.00664999 msecs
Total time: 6650 msecs
Calls count: 1000001

Id: UseToString()
Avg time: 0.016495 msecs
Total time: 16495 msecs
Calls count: 1000001

As you can see even from this test, value based concatenation (your UseToString)
is generally slowest.

But without adding << functionality, value based concatenation is all that you
have for std::string in an expression.


Cheers & hth.,

- Alf
 
F

Francesco

* Francesco: [snip]
I've tried to implement and profile at once all three possibilities
(inserters, toString function with the default + operator, direct
stringstream usage). To be fair between the measurements, I've helped
the "inserters" version as much as possible (since the toString needs
to be called fewer times).

Well, you haven't (see below).

But it doesn't matter here.

I see what you mean: I did not help then as much as possible. In fact,
I helped them as much as I could (actually, I did it by overloading
operator<<() for string, const char* and char, thus avoiding to create
a further ostringstream in those cases).
Not at all. Your timings show the inserters to be superior. And among the two
inserter approaches, which are fastest, the one that doesn't do a lot of extra
needless work per insertion, is  --  not unexpectedly!  --  slightly faster.

Well, yes, slightly faster. But such a difference came as "more or
less" to my eyes, since the "winner" alternated between different
runs ;-)

Of course, I didn't consider the direct ostringstream usage into the
"more or less equal timings" statement, that was the reference
timing ;-)
It would, yes. :)

I guessed right, but I didn't completely get the point. Now I filled
the gap, read below.
Generally that's a good idea, but invoking std::eek:stringstream in each << and
then for each such result extracting a string and copying it plus a
concatenation, is ungood for efficiency because, as Jerry remarked else-thread
or was it up-thread, you're then doing much extra, needless work.

I thought I simply couldn't avoid it (Jerry suggested me to use
ostringstream directly) - and after all, I was looking for ease of
notation (that is, hiding the use of an ostringstream, but still using
<< on the strings). I didn't really consider timing issues before of
your post,

Now I also realize that I simply rehearsed the thread about building
strings on the fly with the wrong supposition that I could take
advantage of applying the << operators directly to the strings.

Not bad, in any case. This gives me the occasion to merge the
improvements I made to my logger class (there in that other thread)
with your suggestions.
Instead do something like (off the cuff)

   class S
   {
   private:
       std::eek:stringstream myStream;

   public:
       S() {}
       S( char const s[] ): myStream( s ) {}
       S( std::string const& s ): myStream( s ) {}

       template< typename T >
       S& operator<<( T const& v )
       {
           myStream << v;
           return *this;
       }

       std::string str() const { return myStream.str(); }
       operator std::string () const { return myStream.str(); }
   };

Here above you made explicit the point that I missed to get in your
previous post.
While in my insertion sequences the leftmost object was a string, in
your code it was an "S" object. I missed to understand it, I replaced
it with a couple of question marks in my mind and I went on :-/

That's pretty bad, because it means that I completely mistaken the
very beginning of that other thread, which I realize I have sort of
hijacked :-/
You haven't tested it. Your timings are dominated by the inefficient conversion
from number to string, and you have very short strings and low number of them,
avoiding all three factors that might make that difference count. It's possible
that you'll see it if you use e.g. sprintf to implement the conversion, and/or
if you use longer strings, and/or if you have more of them.

That means that I should prefer sprintf over ostringstream to get
faster conversions?
I suppose so. But if I use it I wouldn't be taking advantage of stream
manipulators and formatting, I suppose, and I just decided to allow
them in.

I'll keep sprintf out, getting a performance close to the direct
ostringstream usage will be more than enough.

[ snipped code and test results of mine ]
As you can see even from this test, value based concatenation (your UseToString)
is generally slowest.

But without adding << functionality, value based concatenation is all that you
have for std::string in an expression.

Now I understand. Thanks a lot, I've learned a lot of things here,
once more.

I will extend your S class and I'll post it here, shall it be of some
use for anybody else stomping on this thread.

Best regards,
Francesco
 
F

Francesco

Francesco <[email protected]> kirjutas:




sprintf() (or non-standard itoa()) are probably faster than ostringstream
and in case of integers also quite easy to get reasonably robust.

Already for doubles it becomes much more difficult to avoid buffer
overruns. One should use at least snprintf() for anything else than just an
integer, resizing the buffer appropriately when needed. Note that
ostringstream is more typesafe and does the buffer resizing automatically,
so it should be preferred over sprintf() and friends always except when the
profiling shows it becoming a bottleneck.

Thank you for your confirmation Paavo, I'm sticking to ostringstream
for ease of implementation - no need for further optimization yet.

Best regards,
Francesco
 
F

Francesco

* Francesco: [snip]
I suppose you were speaking about an ad-hoc string class that includes
inserters from the beginning, but then that would be something like an
ostringstream,

It would, yes. :)
while my idea was just to add some local helper
function to stream into a std::string for simpler-notation's sake.

Generally that's a good idea, but invoking std::eek:stringstream in each << and
then for each such result extracting a string and copying it plus a
concatenation, is ungood for efficiency because, as Jerry remarked else-thread
or was it up-thread, you're then doing much extra, needless work.

Instead do something like (off the cuff)

   class S
   {
   private:
       std::eek:stringstream myStream;

   public:
       S() {}
       S( char const s[] ): myStream( s ) {}
       S( std::string const& s ): myStream( s ) {}

       template< typename T >
       S& operator<<( T const& v )
       {
           myStream << v;
           return *this;
       }

       std::string str() const { return myStream.str(); }
       operator std::string () const { return myStream.str(); }
   };

So then, here is my mod of your S class (that would be also a mod of
the class posted by Stuart Golodetz in that other thread - I'm unsure
about posting this code there too...)

I only added the ability to feed it with all standard manipulators,
just like I've done in the other thread - seems to be enough:

-------
#include <iostream>
#include <sstream>
#include <iomanip>

class S {
private:
std::eek:stringstream os_stream;
public:
S() {}
S( const char* s ): os_stream(s) {}
S( const std::string& s ): os_stream(s) {}
template<class T> S& operator<<(const T& t) {
os_stream << t;
return *this;
}
S& operator<<(std::eek:stream& (*f) (std::eek:stream&)) {
os_stream << f;
return *this;
}
operator std::string() const {
return os_stream.str();
}
};

int main() {
std::string s = S() << std::fixed << std::setprecision(1)
<< 3.333 << std::endl;
std::string s2 = S() << std::setw(5) << std::setfill('#')
<< std::internal << -42 << std::endl;
std::cout << s << s2;
return 0;
}
-------

The above produces the following output as expected:

-------
3.3
-##42
-------

I don't think it's the case to extend it in order to access active
flags, after all, this class is only meant to build strings on the
fly. I've also removed the str() method, just for the same reason.

Heck, it's a shame, I thought I could make a Columbus' Egg in this
way:

-------
// doesn't work as expected, doesn't compile when used
class SS : public std::eek:stringstream {
public:
SS() {}
SS( const char* s ) : std::eek:stringstream(s) {}
SS( const std::string& s ): std::eek:stringstream(s) {}
operator std::string() const { // doesn't work as expected,
return str(); // 'cause it doesn't compile when
used
}
};
-------

....but the compiles chokes on the implicit string conversion (seems
like the ostringstream resolves to void* and the implicit conversion
mistakes it for const char*, completely overlooking the operator
implemented for the SS class

Never mind, the S class mod above works just fine and performs just
like using ostringstream directly.

Thanks everybody for your help, really appreciated.

Best regards,
Francesco
 
J

Jerry Coffin

[ ... ]
where one should note that for a typical implementation of string
concatenation '+' operator the latter is less clear and to boot is
generally quadratic time, O(e^2), in the number of string elements
e to be concatenated

You're right that operator+ will usually have quadratic time, but
that's an apples to oranges comparison. The more accurate comparison
would be << to +=. We'd normally expect those to mean roughly the
same thing, and work at about the same speed -- in fact, the obvious
implementation of operator<< would be little more than a thunk for
operator+= (or, equivalently, append).
 
A

Alf P. Steinbach

* Jerry Coffin:
[ ... ]
where one should note that for a typical implementation of string
concatenation '+' operator the latter is less clear and to boot is
generally quadratic time, O(e^2), in the number of string elements
e to be concatenated

You're right that operator+ will usually have quadratic time, but
that's an apples to oranges comparison. The more accurate comparison
would be << to +=. We'd normally expect those to mean roughly the
same thing, and work at about the same speed -- in fact, the obvious
implementation of operator<< would be little more than a thunk for
operator+= (or, equivalently, append).

+= associates to the right, thus it's rather cumbersome in expressions.

So << isn't an alternative to +=.

Hence, comparing << to += is pretty meaningless.


Cheers & hth.,

- Alf
 
J

Jerry Coffin

* Jerry Coffin:
[ ... ]
where one should note that for a typical implementation of string
concatenation '+' operator the latter is less clear and to boot is
generally quadratic time, O(e^2), in the number of string elements
e to be concatenated

You're right that operator+ will usually have quadratic time, but
that's an apples to oranges comparison. The more accurate comparison
would be << to +=. We'd normally expect those to mean roughly the
same thing, and work at about the same speed -- in fact, the obvious
implementation of operator<< would be little more than a thunk for
operator+= (or, equivalently, append).

+= associates to the right, thus it's rather cumbersome in expressions.

So << isn't an alternative to +=.

Hence, comparing << to += is pretty meaningless.

While it's true that it doesn't work as well for chaining, at least
there's _some_ circumstance under which it does pretty much the same
thing -- which is not true of operator+.

If you really want something that works like operator<<, there's not
much of a substitute for it, and if you compare it to something
different, you're going to have to live with the fact that it is
different.

That said, I stand by the fact that an ostringstream is really built
for this purpose, so that's what I'd use first. If and only if I
profiled and found it to be a problem, I'd try something else. I
don't think that's likely very often, but if it did happen, then
overloading operator<< would be an obvious alternative. I'll repeat
though: I think justification for that is probably pretty rare.
 
A

Alf P. Steinbach

* Jerry Coffin:
* Jerry Coffin:
[ ... ]

where one should note that for a typical implementation of string
concatenation '+' operator the latter is less clear and to boot is
generally quadratic time, O(e^2), in the number of string elements
e to be concatenated
You're right that operator+ will usually have quadratic time, but
that's an apples to oranges comparison. The more accurate comparison
would be << to +=. We'd normally expect those to mean roughly the
same thing, and work at about the same speed -- in fact, the obvious
implementation of operator<< would be little more than a thunk for
operator+= (or, equivalently, append).
+= associates to the right, thus it's rather cumbersome in expressions.

So << isn't an alternative to +=.

Hence, comparing << to += is pretty meaningless.

While it's true that it doesn't work as well for chaining, at least
there's _some_ circumstance under which it does pretty much the same
thing -- which is not true of operator+.

If you really want something that works like operator<<, there's not
much of a substitute for it, and if you compare it to something
different, you're going to have to live with the fact that it is
different.

The above is complete balderdash.

First, it's you who have made an inappropriate comparision. Comparing << to +=
is just meaningless. They're not competing operators, not used for same purpose.
It is like comparing a hair dryer to a toaster just because they share the
characteristic of being electric appliances that apply heat to something. It's a
completely irrelevant characteristic when you want to dry your hair, or for that
matter, when you want toast a slice of bread, or just about anything.

Second, it's you who misleadingly and incorrectly, but I think unwittingly, just
caught up by the moment and not really thinking about it, have described the
proper comparision, << versus +, as comparing apples to oranges.

Third, if anyone at all have any problem "living with" the fact that + and <<
are different, that would be you, at least it's not me: I haven't complained, to
me it's perfectly all right that << is generally far more efficient.

As well as generally also more convenient. :)

That said, I stand by the fact that an ostringstream is really built
for this purpose, so that's what I'd use first. If and only if I
profiled and found it to be a problem, I'd try something else. I
don't think that's likely very often, but if it did happen, then
overloading operator<< would be an obvious alternative. I'll repeat
though: I think justification for that is probably pretty rare.

No, I think it's common. At least that's my experience. YMMV, as they say: if
you have an intuitive hindbrain grasp of the real situation but are consciously
suppressing that, then I think you'd tend to use awkward non-expression based
code, what I call "imperative code", to avoid the inefficiencies, and then you'd
probably be so accustomed to that that you'd regard that as normal. You're then
paying a cost that you don' see, more code and more complex code, like not
seeing the jungle for all the trees, because you're so accustomed to it. The
cost of efficiency is *not* the main thing, it just influences the choice of
operator (namely, << instead of +) to use for easier expression based code.


Cheers,

- Alf
 
J

Jerry Coffin

[ ... ]
The above is complete balderdash.

Quite correct -- except that you misspelled "below" as "above".
First, it's you who have made an inappropriate comparision. Comparing << to +=
is just meaningless.

Nonsense. Given a sane implementation of operator<< for strings,
"x+=y;" and "x<<y;" have identical effects. It's only when/if you
want to chain the operators that you get differences.

Now, if you honestly want to overload "x+y;" to mean the same thing
as either of the above, or claim that anybody else would do so,
you've clearly just lost any grip you may have ever had on reality.

The fact is, that such a claim is utterly insane, and we both know
it.

Now, it is true that it's possible to use operator+ _in conjunction
with operator=_ to produce a somewhat similar effect. It's also true
that doing so may be less efficient -- at least part of the time,
with some compilers, etc.

Then again, depending on a compiler's implementation of inlining
compared to its implementation of NRVO, URVO and copy elision in
general, it's entirely possible that the two might be about the same
speed, and even barely possible that the version using operator+ and
operator= would be faster.

That, however, does NOT change the fact that your attempt at
comparing operator+ to operator<< simply makes no sense. While it's
_possible_ to make them to the same thing, such an overload would be
an obvious travesty. Given any sanity at all in the overloading, the
two cannot and most not do the same things.
 
A

Alf P. Steinbach

* Jerry Coffin:
[ ... ]
The above is complete balderdash.

Quite correct -- except that you misspelled "below" as "above".
First, it's you who have made an inappropriate comparision. Comparing << to +=
is just meaningless.

Nonsense. Given a sane implementation of operator<< for strings,
"x+=y;" and "x<<y;" have identical effects. It's only when/if you
want to chain the operators that you get differences.

Your argument that "only" the differences are different, and that it's "only" in
the context of the relevant usage that there are differences, is plain idiocy.

It is a fallacy.

Given that, it doesn't really matter that you forgot a difference or two.

Now, if you honestly want to overload "x+y;" to mean the same thing
as either of the above, or claim that anybody else would do so,
you've clearly just lost any grip you may have ever had on reality.

The first part of that is something that you have cooked up out thin air, a
strawman position (and that's a second fallacy).

The last part is a personal attack (and that's a third fallacy).

Just for your information: it reflects *very* badly on you to invent an
untenable strawman argument, falsely attribute it to me as my position (even
with an "if"), and on that basis describing me as currently insane and as of
having displayed signs of mental problems earlier, neither of which is true.

Such an attack means that at least in the heat of writing you lacked both
intelligence and decency.

This is Usenet, which is archived.

If you care about how you are perceived, then this would be a good place to post
an apology.

The fact is, that such a claim is utterly insane, and we both know
it.

Describing your strawman, invented from thin air and falsely attributed to me,
as an insane idea...

Interesting.

Anyway, that's a fourth fallacy.

Now, it is true that it's possible to use operator+ _in conjunction
with operator=_ to produce a somewhat similar effect. It's also true
that doing so may be less efficient -- at least part of the time,
with some compilers, etc.

Then again, depending on a compiler's implementation of inlining
compared to its implementation of NRVO, URVO and copy elision in
general, it's entirely possible that the two might be about the same
speed, and even barely possible that the version using operator+ and
operator= would be faster.

That, however, does NOT change the fact that your attempt at
comparing operator+ to operator<< simply makes no sense. While it's
_possible_ to make them to the same thing, such an overload would be
an obvious travesty. Given any sanity at all in the overloading, the
two cannot and most not do the same things.

I'm not sure what you're trying to express above, since much of it is
meaningless and emotive.

It seems that you feel ("an obvious travesty") strongly about which operator
should be used for what, but lacking any technical arguments all you can do is a
personal attack.

Consider: a person who uses very obvious fallacies in an argument, and who
accuses others of being insane.


Cheers,

- Alf
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,582
Members
45,066
Latest member
VytoKetoReviews

Latest Threads

Top