best efficient and readable way to concatenate strings (or the best trade-offs)

D

Diego Martins

Since C++ (and STL) have many ways to do string concatenation, I want
to hear (read) from you how you do to concatenate strings with other
strings and other types. The approaches I know are:

-- ostringstream
this does the job well, but:
* all types involved have to support operator<<
* we will lose some readibility in the code because we will always
have to create a temp object to do the concatenation

int n;
float x;
....
ostringstream temp;
temp << "we bought " << n << " items at " << x << " price";
notebook.add(temp.str());
// three liner :(


-- string::eek:perator+
most advantage is we can built all the string using a one liner and
passing the result to string const &, but:
* we have to ensure all members are of string type
* to achieve that, we can use boost::lexical_cast or custom functions
to convert our types/classes to string

int n;
float x;
....
notebook.add("we bought " + toString(n) + " items at " + toString(x) +
" price");
// one liner!! :)

(but is there actually a gain doing that?)

and we have to implement toString(). which way is better?
lexical_cast? ostringstream? overloading (or specializing) for each
involved types? (ints and floats can be converted faster using some
hacks)


-- ostringstream wrapped in a (family) of functions
this technique combines the stream versatility with the oneliner
concatenation thing, but without RVO, I am not sure we will gain
anything:

int n;
float x;
....
notebook.add(concat("we bought ",n," items at ",x," price"));
// one liner!! :)

template<typename A, typename B, typename C, typename D>
string concat(A a, B b, C c, D d) {
ostringstream temp;
temp << a << b << c << d;
return temp.str();
}

this works, but one does not need to be a genius to figure out we have
to define a family of concat functions to handle the different number
of parameters

any ideas?

thanks!!!

Diego
HP
 
T

Thomas J. Gritzan

Diego said:
Since C++ (and STL) have many ways to do string concatenation, I want
to hear (read) from you how you do to concatenate strings with other
strings and other types. The approaches I know are: [...]
any ideas?

Just another way:
boost.format <http://www.boost.org/libs/format/index.html>

Use what is most readable and optimize when your profiler says so.
 
?

=?ISO-8859-1?Q?Erik_Wikstr=F6m?=

Since C++ (and STL) have many ways to do string concatenation, I want
to hear (read) from you how you do to concatenate strings with other
strings and other types. The approaches I know are:

[snip ostringstream]
-- string::eek:perator+
most advantage is we can built all the string using a one liner and
passing the result to string const &, but:
* we have to ensure all members are of string type
* to achieve that, we can use boost::lexical_cast or custom functions
to convert our types/classes to string

int n;
float x;
...
notebook.add("we bought " + toString(n) + " items at " + toString(x) +
" price");
// one liner!! :)

(but is there actually a gain doing that?)

and we have to implement toString(). which way is better?
lexical_cast? ostringstream? overloading (or specializing) for each
involved types? (ints and floats can be converted faster using some
hacks)

If you are mainly concerned with user defined types you can implement

std::string operator+(const std::string&, const myType&)
and
std::string operator+(const char*, const MyType&)

which would make it possible to write things like:

std::cout << "Value: " + myVal + "\n";

where myVal is of type MyType.
 
A

Alan Johnson

Diego said:
Since C++ (and STL) have many ways to do string concatenation, I want
to hear (read) from you how you do to concatenate strings with other
strings and other types. The approaches I know are:

-- ostringstream
this does the job well, but:
* all types involved have to support operator<<
* we will lose some readibility in the code because we will always
have to create a temp object to do the concatenation

int n;
float x;
...
ostringstream temp;
temp << "we bought " << n << " items at " << x << " price";
notebook.add(temp.str());
// three liner :(


-- string::eek:perator+
most advantage is we can built all the string using a one liner and
passing the result to string const &, but:
* we have to ensure all members are of string type
* to achieve that, we can use boost::lexical_cast or custom functions
to convert our types/classes to string

int n;
float x;
...
notebook.add("we bought " + toString(n) + " items at " + toString(x) +
" price");
// one liner!! :)

(but is there actually a gain doing that?)

and we have to implement toString(). which way is better?
lexical_cast? ostringstream? overloading (or specializing) for each
involved types? (ints and floats can be converted faster using some
hacks)


-- ostringstream wrapped in a (family) of functions
this technique combines the stream versatility with the oneliner
concatenation thing, but without RVO, I am not sure we will gain
anything:

int n;
float x;
...
notebook.add(concat("we bought ",n," items at ",x," price"));
// one liner!! :)

template<typename A, typename B, typename C, typename D>
string concat(A a, B b, C c, D d) {
ostringstream temp;
temp << a << b << c << d;
return temp.str();
}

this works, but one does not need to be a genius to figure out we have
to define a family of concat functions to handle the different number
of parameters

any ideas?

thanks!!!

Diego
HP

I'm a fan of classes like the following:
#include <sstream>
#include <string>

class concat
{
public:
template <typename T>
explicit concat(const T & t)
{
m_out << t ;
}

template <typename T>
concat & operator()(const T & t)
{
m_out << t ;
return *this ;
}

std::string str() const
{
return m_out.str() ;
}
private:
std::eek:stringstream m_out ;
} ;

#include <iostream>

int main()
{
int n = 4 ;
float x = .99 ;
std::string test = concat("We bought ")(n)(" items at ")(x)("
price").str() ;
std::cout << test << std::endl ;
}
 
A

Alan Johnson

Diego said:
Since C++ (and STL) have many ways to do string concatenation, I want
to hear (read) from you how you do to concatenate strings with other
strings and other types. The approaches I know are:

-- ostringstream
this does the job well, but:
* all types involved have to support operator<<
* we will lose some readibility in the code because we will always
have to create a temp object to do the concatenation

int n;
float x;
...
ostringstream temp;
temp << "we bought " << n << " items at " << x << " price";
notebook.add(temp.str());
// three liner :(


-- string::eek:perator+
most advantage is we can built all the string using a one liner and
passing the result to string const &, but:
* we have to ensure all members are of string type
* to achieve that, we can use boost::lexical_cast or custom functions
to convert our types/classes to string

int n;
float x;
...
notebook.add("we bought " + toString(n) + " items at " + toString(x) +
" price");
// one liner!! :)

(but is there actually a gain doing that?)

and we have to implement toString(). which way is better?
lexical_cast? ostringstream? overloading (or specializing) for each
involved types? (ints and floats can be converted faster using some
hacks)


-- ostringstream wrapped in a (family) of functions
this technique combines the stream versatility with the oneliner
concatenation thing, but without RVO, I am not sure we will gain
anything:

int n;
float x;
...
notebook.add(concat("we bought ",n," items at ",x," price"));
// one liner!! :)

template<typename A, typename B, typename C, typename D>
string concat(A a, B b, C c, D d) {
ostringstream temp;
temp << a << b << c << d;
return temp.str();
}

this works, but one does not need to be a genius to figure out we have
to define a family of concat functions to handle the different number
of parameters

any ideas?

thanks!!!

Diego
HP

(Apologies if this message comes through twice. I'm having server
troubles.)

I'm a fan of the following syntax for operations that can take an
indefinite number of parameters:
#include <sstream>
#include <string>

class concat
{
public:
template <typename T>
explicit concat(const T & t)
{
m_out << t ;
}

template <typename T>
concat & operator()(const T & t)
{
m_out << t ;
return *this ;
}

std::string str() const
{
return m_out.str() ;
}
private:
std::eek:stringstream m_out ;
} ;

#include <iostream>

int main()
{
int n = 4 ;
float x = .99 ;
std::string test = concat("We bought ")(n)(" items at ")(x)("
price").str() ;
std::cout << test << std::endl ;
}
 
D

Diego Martins

I'm a fan of the following syntax for operations that can take an
indefinite number of parameters: [snip]
int main()
{
int n = 4 ;
float x = .99 ;
std::string test = concat("We bought ")(n)(" items at ")(x)("
price").str() ;
std::cout << test << std::endl ;
}

thanks for all responses. the above approach is very nice. I liked the
boost::format too (seems to be very powerful)

I believe the syntax above could be improved to something like this:
std::string test = concat("we bought") + n + " items at " + x + "
price";

concat class must have a templated operator+() as a member function
template<typename T>
concat & concat::eek:perator+(T value) { stream << value; return *this; }

and an operator string to retrieve/compute the result
string concat::eek:perator string(); { return stream.str(); }


if optimization is an issue, we might find a way to use a vector of
pointers (and typeinfos? o__O) to concat all members at a time in the
operator string (a custom concatenation? a reserve and vector of
chars? it could be trickier than one can imagine..)

more ideas?
Diego
 

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

Forum statistics

Threads
473,768
Messages
2,569,575
Members
45,053
Latest member
billing-software

Latest Threads

Top