Okay, still a slight ambiguity, sorry. If I take you literally,
partial template specialization is still the answer -- it's certainly
sufficient for the example code you've posted. It's also sufficient if
you have a common "Object" base class for everything that isn't a POD.
If that wasn't what you meant, then I'd follow other people's
suggestion to use boost::is_pod<T>. The Boost libraries are of
phenomenal importance, so you should install them and learn to love
them regardless of whether you wind up needing them in this particular
case. Better yet, go see how is_pod is implemented.
I'll offer my own version of "how to do it with boost," though I must
apologize that I can't test this code myself right now as I'm in the
middle of a RedHat install, and attempting this with MSVC 6.0 sounds
like a cruel joke to play on myself and that dated compiler. Anyway,
this is the code I'd generate:
#include <string>
#include <boost/type_traits/is_pod.hpp> // <-- should use forward
slashes and angle brackets as here
#include <boost/static_assert.hpp>
class Stream {
private:
template <class T> class Stream & rawWrite(
friend template <class T, bool isPod> operator<<(Stream & os, T
obj);
};
template <class T, bool isPod>
Stream & operator<<(Stream & os, T nonPodObj) {
nonPodObj.writeToStream(os);
return os;
}
template <class T>
Stream & operator<< <T, true>(Stream & os, T pod) {
BOOST_STATIC_ASSERT(boost::is_pod<T>::value);
os.rawWrite(&pod, sizeof(T));
}
class Base {
public:
Stream & writeToStream(Stream & os);
};
/*** END CODE LISTING ***/
The above should work (again, untested -- sorry) as long as you don't
directly subvert it -- if you're worried about someone doing that, you
can put in another static assertion to guard against it, or structure
it a little differently by delegating to a helper based on the value of
is_pod.
A couple of notes on some pitfalls to avoid from the other (otherwise
perfectly helpful) suggestions you received:
* Never do a "using namespace std" declaration at a wider scope than an
individual function. It pollutes the global namespace and completly
defeats the purpose of the std namespace. Make use of using-directives
(e.g. "using std::string") instead, or explicitly qualify upon use.
* operator<<'s signature should be as I've given it -- it takes a
reference (non-const) to the stream as well as the object, and returns
the stream by reference. If you don't do it this way, you can't chain
them together. As such, it should not be a member function, either.
* Don't #include <iostream> if you're not using it.
* Make sure that you know the criteria is_pod uses, thoroughly. Check
the standard if you don't know the precise definition (it's not
entirely obvious), or the boost::is_pod documentation.
There are a lot of variants on how exactly to do the decision logic
within the bounds of partial template specialization. I heartily
recommend "Modern C++ Design" by Andrei Alexandrescu (waves @ Andrei --
I was a CS undergrad at UW during his grad stint there, I believe) and
"C++ Template Metaprogramming" by Abrahams and Gurtovoy.
Luke