In our production code, we cannot use Boost or C++0x. Formatting strings using sprintf
or stringstream
is annoying in this case, and this prompted me to write my own little Formatter
class. I am curious if the implementation of this class or the use of it introduces any Undefined Behavior.
In particular, is this line fully-defined:
Reject( Formatter() << "Error Recieved" << 42 << " " << some_code << " '" << some_msg << "'");
My belief is that it is OK, but I wanted peer-review.
Three main points of concern:
- Is there a double-assignment within a single sequence point? Is it UB?
- Do I have a problem with the lifetime of temporaries?
- Does my
Formatter
class (or the intended use of it) introduce any UB?
The Formatter
class has both a (templatized) operator<<
and an operator std::string
. The intent is to use the Formatter()
class as a temporary in place of a std::string
parameter for any function taking a const std::string&
.
Here is the class definition:
class Formatter
{
public:
Formatter() {};
template<class Field> Formatter& operator<<(Field f)
{
ss_ << f;
return *this;
}
operator std::string() const { return ss_.str(); }
private:
std::stringstream ss_;
};
And here is a complete test harness, including the above definition. You should be able to compile & run as-is. Do you see any UB?
#include <cstdlib>
#include <string>
#include <sstream>
#include <iostream>
class Formatter
{
public:
Formatter() {};
template<class Field> Formatter& operator<<(Field f)
{
ss_ << f;
return *this;
}
operator std::string() const { return ss_.str(); }
private:
std::stringstream ss_;
};
void Reject(const std::string& msg)
{
std::cout << "Recieved Message: '" << msg << "'" << std::endl;
}
int main()
{
const char& some_code = 'A';
const char* some_msg = "Something";
Reject( Formatter() << "Error Recieved" << 42 << " " << some_code << " '" << some_msg << "'");
}