Eliminate repetition in C ++ code?

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 the recurrence? I want to use templates, but I only want it for the following types: const char * int, unsigned and size_t

+6
c ++ templates dry
source share
2 answers

Indeed, in C ++ vanilla, you either write manually for certain types, or use a template like dirkgently.

However, 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 create a compile-time error with the TYPE_NOT_ALLOWED message embedded in it if the compiled type is not in the type list.

Also, since Boost is required for this answer, I just used lexical_cast . You will notice that you are repeating this code, and this is bad. Consider wrapping this functionality in a function.


If you cannot use Boost, you can easily imitate this with some traits like:

 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; } 

It will also generate a compile-time error if the statement is not executed, although the code is not so sexy.: (<- Not sexy

+6
source share

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; } 
+1
source share

All Articles