tags:

views:

229

answers:

2

Given the following:

StreamLogger& operator<<(const char* s) {
  elements.push_back(String(s));
  return *this;
}

StreamLogger& operator<<(int val) {
  elements.push_back(String(asString<int>(val)));
  return *this;
}

StreamLogger& operator<<(unsigned val) {
  elements.push_back(String(asString<unsigned>(val)));
  return *this;
}

StreamLogger& operator<<(size_t val) {
  elements.push_back(String(asString<size_t>(val)));
  return *this;
}

is there a way to eliminate repetition? I want to use templates, but I only want it for the following types: const char* int, unsigned, and size_t

+1  A: 

Something like this should work:

template <class T>
StreamLogger& operator<<(T val) {
  istringstream s;
  s << val;
  elements.push_back(s.str()); // assuming elements is a vector<string>
  return *this;
}
dirkgently
but OP wants it only for particular types.
Naveen
@Naveen: Not sure if that he wants a restricted template or if those are the _only_ types that he needs. Some clarification will be of help.
dirkgently
@*: FWIW, checking for particular types can be done with Boost.Type Traits and `BOOST_STATIC_ASSERT`.
dirkgently
+6  A: 

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

GMan
And unfortunately the compiler error might not be sexy either :)
Matthieu M.