Overload operator += in template class with std::enable_if metafunction

1.5k Views Asked by At

I have a string class implemented as a class template like:

template <class T>
class HGStringBasic
{
//...
public:
//...
    HGStringBasic& operator += (const T* rhs)
    {
        //...
    }

    template <class U, std::enable_if_t<std::is_same<U, char>::value>* = nullptr>
    HGStringBasic& operator += (const U* rhs)
    {
        //...
    }
//...   
}

The code is C++ 11 standard conform. The goal was to implement an overloaded operator += (const char) which is only used, if class T of the template is for instance "wchar_t".

I would like to know, how i can achieve the same result if the compiler don't understand C++11.

UPDATE: Sry i'm new to stackoverlow and i haven't seen, that my code wasn't fully shown in the code block. I have now updated my code sniped so far. I have also corrected a mistake within the template argument list from the template function operator += (), TartanLlama you're absolutly right, is_same<T, char> must be is_same<U, char>.

4

There are 4 best solutions below

0
Christian On BEST ANSWER

Now i have figured it out, no c++11 and with the already known metafunctions. Big thanks to Barry for the hint with specifying the return type.

Here is what i did:

#include <type_traits>

template <class _ElemT>
class HGStringBasic
{
    public:
        // Append char* or wchar_t* depending on specialization
        HGStringBasic& operator += (const _ElemT* rhs)
        {
            return *this;
        }

        // Allow char* if specialization is wchar_t
        template <class U>
        typename std::enable_if<std::is_same<U, char>::value, HGStringBasic&>::type operator += (const U* rhs)
        {
            // Convert ansistring to widestring
            return *this;
        }

        // Allow wchar_t* if specialization is char
        template <class U>
        typename std::enable_if<std::is_same<U, wchar_t>::value, HGStringBasic&>::type operator += (const U* rhs)
        {
            // Convert widestring to ansistring
            return *this;
        }
};
0
Roman Dobrovenskii On

enable_if doesn't depend on C++11 functionality. It was implemented way before C++11 in boost library almost the same way it is implemented now. Here's a possible implementation taken from cppreference.com:

template<bool B, class T = void>
struct enable_if {};

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

This would work perfectly fine in C++ prior to C++11.

0
SergeyA On

First of all, enable_if/is_same can be easily be implemented in C++2003. Boost has them, for example, or you can create those yourserlf - it's a good practice.

Second, if you do not want to use enable_if, you can simply provide a specialization of myString for w_char. To reduce amount of coding, put this in some base class, derive myString from the base class and provide specialization of base class.

2
Barry On

First of all, your C++11 does not work. If I tried to do:

myString<int> x;
x += new int(4);

Your operator+= would fail to compile. SFINAE only applies in the immediate context of substitution - but T isn't in the immediate context here, only U is. So the correct thing would be:

template <class U, 
          class _T=T,
          class = std::enable_if_t<std::is_same<_T, char>::value>>
myString& operator += (const U* rhs);

Now back to the original question. How do we write the above in C++03? Same idea. We just can't have default template arguments. But the same principle applies: we need a substitution failure in the immediate context:

template <typename T, typename U, typename R>
struct allow_for_char;

template <typename U, typename R>
struct allow_for_char<char, U, R> { typedef R type; };

Which you could then use to specify the return type:

template <class U>
typename allow_for_char<T, U, myString&>::type
operator += (const U* rhs);