// the AMString class is just a wrapper class around std::string, so I can
// just replace my own string class by a one using std::string, without
// changing the rest of the code
// in the .h
class AMString
{
protected:
std::string m_str;
public:
AMString(void);
// ...
// operators +
AMString operator + (const float value);
AMString operator + (const int value);
// ...
// ...
};
// in the .cpp :
AMString AMString::operator + (const float value)
{
std::stringstream ss;
std::string str;
ss << m_str;
ss << value;
ss >> str;
return(AMString(str));
}
AMString AMString::operator + (const int value)
{
std::stringstream ss;
std::string str;
ss << m_str;
ss << value;
ss >> str;
return(AMString(str));
}
operator + with various parameter types
Hi,
Here's a bit of code I'm currently using :
2 questions :
- Is it the correct way of concantenating a number to a std::string ?
- The code for floats and ints is exactly the same. Is there a way to specify an operator that would accept any type of parameter, so that I only have on operator + defined which would accept floats, ints, etc. ??
Thx for any help
Quote:Original post by paic
Hi,
Here's a bit of code I'm currently using :
*** Source Snippet Removed ***
2 questions :
- Is it the correct way of concantenating a number to a std::string ?
There are a few variants, but all are pretty much based on stringstreams in one way or another. Your way is OK.
Quote:Original post by paic
- The code for floats and ints is exactly the same. Is there a way to specify an operator that would accept any type of parameter, so that I only have on operator + defined which would accept floats, ints, etc. ??
Thx for any help
Can be solved with templates.
template<typename T> AMString operator + (T value);template<typename T> AMString AMString::operator + (T value){ std::stringstream ss; std::string str; ss << m_str; ss << value; ss >> str; return(AMString(str));}
Now you can use operator + with any datatype that can be passed to an ostream with operator <<.
That won't work with strings that contain spaces. I also recommend making operator+ a non-member function implemented in terms of a member operator+=. This has the dual benefits of having your implementation in only one place (operator+=) and allowing type conversions on both arguments of operator+. You probably want something like:
Those templates will allow concatenation to an AMString of any class which has an operator<< which can be called for an output stream.
Enigma
#include <iostream>#include <sstream>#include <string>class AMString{ public: AMString(std::string const & s) : m_str(s) { } std::string str() const { return m_str; } AMString & operator+=(AMString const & value); template < typename Type > AMString & operator+=(Type const & value); private: std::string m_str;};AMString & AMString::operator+=(AMString const & value){ m_str += value.m_str; return *this;}template < typename Type >AMString & AMString::operator+=(Type const & value){ std::ostringstream ss; ss << value; m_str += ss.str(); return *this;}AMString operator+(AMString lhs, AMString const & rhs){ return lhs += rhs;}template < typename Type >AMString operator+(AMString lhs, Type const & rhs){ return lhs += rhs;}template < typename Type >AMString operator+(Type const & lhs, AMString const & rhs){ // possibly not the most efficient implementation, but saved me having to write more code return (AMString("") += lhs) += rhs;}int main(){ AMString str1("Hello"); str1 += " World!"; std::cout << (AMString("Hello") + AMString(" World!")).str() << '\n'; std::cout << str1.str() << '\n'; std::cout << (str1 + ' ' + 2).str() << '\n'; std::cout << (1 + (": " + str1)).str() << '\n';}
Those templates will allow concatenation to an AMString of any class which has an operator<< which can be called for an output stream.
Enigma
Oh, and I forgot, when dealing with templates you can't separate declaration and definition as you have in your original code. You must put the function definition in the header aswell.
edit: Some suggestions by Enigma I didn't think about, so focus on his reply instead of mine.
edit: Some suggestions by Enigma I didn't think about, so focus on his reply instead of mine.
Ah, I didn't know that you could have a template method in a non-template class. That will help a lot, thx ^^
And for the whitespace, yes, I just came accross a post here ^^
I replaced "ss >> str; return(AMString(str));" by "return(AMString(ss.str()))";
It saves 1 line of code and don't stop at the whitespaces.
@Enigma : I already use the operator += in my operators +. In the code snippet, it was just an example. In my final code, operator + uses operator +=. But I don't understand what you mean by "and allowing type conversions on both arguments of operator+"
And for the whitespace, yes, I just came accross a post here ^^
I replaced "ss >> str; return(AMString(str));" by "return(AMString(ss.str()))";
It saves 1 line of code and don't stop at the whitespaces.
@Enigma : I already use the operator += in my operators +. In the code snippet, it was just an example. In my final code, operator + uses operator +=. But I don't understand what you mean by "and allowing type conversions on both arguments of operator+"
By "allowing type conversion on both arguments" I mean the following:
Of course, for your situation the chances of having a class which has an implicit conversion to AMString but does not have a operator<< usable with output streams are pretty slim, but since there are no disadvantages to using a non-member operator+ I would still use them for consistency.
Enigma
#include <string>class Widget1{ public: Widget1(std::string const & string); Widget1 operator+(Widget1 const & w);};class Widget2{ public: Widget2(std::string const & string);};Widget2 operator+(Widget2 const & lhs, Widget2 const & rhs);int main(){ Widget1 w1_1("widget1 1"); Widget2 w2_1("widget2 1"); std::string extra = "extra"; // OK, compiler constructs a temporary Widget1 object from extra and // calls Widget1::operator+(Widget1 const &) // type conversion on second parameter Widget1 w1_2 = w1_1 + extra; // ERROR, compiler will not perform type conversions on the "this" // parameter of member functions // no type conversion on first parameter Widget1 w1_3 = extra + w1_1; // OK, compiler constructs a temporary Widget2 object from extra and // calls operator+(Widget2 const &, Widget2 const &) // type conversion on second parameter Widget2 w2_2 = w2_1 + extra; // OK, compiler constructs a temporary Widget2 object from extra and // calls operator+(Widget2 const &, Widget2 const &) // type conversion on first parameter Widget2 w2_3 = extra + w2_1;}
Of course, for your situation the chances of having a class which has an implicit conversion to AMString but does not have a operator<< usable with output streams are pretty slim, but since there are no disadvantages to using a non-member operator+ I would still use them for consistency.
Enigma
Ok, I've tried what you said Enigma. But I have problems with the templates. I need to declare and define the template operators + in the .h, but if I do that, I have plenty of "blablah already defined in blahblah.obj" errors :/
It only cause problems with global operator +.
EDIT : ok, was my mistake, I made a typo ^^''
It only cause problems with global operator +.
EDIT : ok, was my mistake, I made a typo ^^''
This topic is closed to new replies.
Advertisement
Popular Topics
Advertisement