Really, in "vanilla" C++ you either write the by hand, for specific types, or you use a template like dirkgently suggested.
That said, if you can use Boost this does what you want:
template <class T>
StreamLogger& operator<<(T val)
{
typedef boost::mpl::vector<const char*, int,
unsigned, size_t> allowed_types;
BOOST_MPL_ASSERT_MSG(boost::mpl::contains<allowed_types, T>::value,
TYPE_NOT_ALLOWED, allowed_types);
// generic implementation follows
elements.push_back(boost::lexical_cast<std::string>(val));
return *this;
}
This will generate a compile-time error with the message TYPE_NOT_ALLOWED
embedded in it if the type being compiled is not contained in the typelist.
Also, since this answer requires Boost I just used lexical_cast
. You'll note you're repeating that code, and that's bad. Consider wrapping that functionality into a function.
If you aren't able to use Boost, you can simulate this pretty easily with some type traits:
template <typename T, typename U>
struct is_same
{
static const bool value = false;
};
template <typename T>
struct is_same<T, T>
{
static const bool value = true;
};
template <bool>
struct static_assert;
template <>
struct static_assert<true> {}; // only true is defined
// not the best, but it works
#define STATIC_ASSERT(x) static_assert< (x) > _static_assert_
template <class T>
StreamLogger& operator<<(T val)
{
STATIC_ASSERT(is_same<const char*, T>::value ||
is_same<int, T>::value ||
is_same<unsigned, T>::value ||
is_same<size_t, T>::value);
// generic implementation follows
elements.push_back(boost::lexical_cast<std::string>(val));
return *this;
}
This will also generate a compile-time error if the assert fails, though the code isn't as sexy. :( <- Not sexy