Search code examples
c++overloadingoverload-resolution

how to avoid many similar overloads for C strings


Here is the code:

template <typename L, typename R> bool eq (const L& lhs, const R& rhs) { return lhs == rhs; }

template<int N> bool eq(char* lhs,           const char(&rhs)[N]) { return String(lhs).compare(rhs) == 0; }
template<int N> bool eq(const char(&lhs)[N], char* rhs)           { return String(lhs).compare(rhs) == 0; }
inline          bool eq(char* lhs,           char* rhs)           { return String(lhs).compare(rhs) == 0; }
inline          bool eq(const char* lhs,     const char* rhs)     { return String(lhs).compare(rhs) == 0; }
inline          bool eq(char* lhs,           const char* rhs)     { return String(lhs).compare(rhs) == 0; }
inline          bool eq(const char* lhs,     char*  rhs)          { return String(lhs).compare(rhs) == 0; }

I have to do this for neq/lt/gt/lte/gte and not just for equality. Maybe I've already missed something.

Is there a way to not list all the possible combinations of C string types?

Also C++98.

EDIT: >> here << is an online demo with the problem


Solution

  • Decay an array type to pointer:

    template<class T>
    struct decay_array { typedef T type; };
    template<class T, size_t N>
    struct decay_array<T[N]> { typedef T* type; };
    template<class T>
    struct decay_array<T[]> { typedef T* type; };
    

    Check that a type is not a pointer to (possibly const) char:

    template<class T>
    struct not_char_pointer { enum { value = true }; };
    template<>
    struct not_char_pointer<char*> { enum { value = false }; };
    template<>
    struct not_char_pointer<const char*> { enum { value = false }; };
    

    Now check that a type is not a pointer to or array of (possibly const) char:

    template<class T>
    struct can_use_op : not_char_pointer<typename decay_array<T>::type> {};
    

    Reimplement std::enable_if:

    template<bool, class = void>
    struct enable_if {};
    template<class T>
    struct enable_if<true, T> { typedef T type; };
    

    and use it to constrain your template:

    template <typename L, typename R> 
    typename enable_if<can_use_op<L>::value || can_use_op<R>::value, bool>::type 
    eq (const L& lhs, const R& rhs) { return lhs == rhs; }
    

    Then just one overload is enough:

    inline bool eq(const char* lhs, const char* rhs) { return String(lhs).compare(rhs) == 0; }