使用std::enable_if元函数重载模板类中的操作符+=

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

本文关键字:操作符 重载 enable std if 函数 使用      更新时间:2023-10-16

我有一个字符串类实现为类模板,如:

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)
    {
        //...
    }
//...   
}

代码符合c++ 11标准。目标是实现一个重载操作符+= (const char),该操作符仅在模板的类T为"wchar_t"时使用。

我想知道,如果编译器不理解c++ 11,我怎么能达到同样的结果。

更新:对不起,我是新的stackoverlow,我还没有看到,我的代码没有完全显示在代码块。到目前为止,我已经更新了我的代码。我还从模板函数操作符+=()中纠正了模板参数列表中的错误,TartanLlama你是绝对正确的,is_same<T, char>必须是is_same<U, char>

首先,在c++ 2003中可以很容易地实现enable_if/is_same。例如,Boost有它们,或者您可以自己创建它们——这是一个很好的实践。

第二,如果不想使用enable_if,可以简单地为w_char提供myString的专门化。为了减少编码量,将其放在某个基类中,从基类派生myString并提供基类的专门化。

enable_if不依赖于c++ 11的功能。它在c++ 11之前就在boost库中实现了,与现在的实现方式几乎相同。下面是一个可能的实现,取自cppreference.com:

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

首先,你的c++ 11不能工作。如果我试着做:

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

您的operator+=将无法编译。SFINAE仅适用于替代的直接上下文中,但T不在这里的直接上下文中,只有U是。所以正确的做法是:

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

现在回到最初的问题。我们如何在c++ 03中编写上述代码?同样的想法。我们只是不能有默认的模板参数。但同样的原则也适用:我们需要在直接上下文中出现替换失败:

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

你可以用它来指定返回类型:

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

现在我已经弄清楚了,没有c++11和已经知道的元函数。非常感谢Barry关于指定返回类型的提示。

我是这样做的:

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