【问题标题】:Overload operator += in template class with std::enable_if metafunction使用 std::enable_if 元函数在模板类中重载运算符 +=
【发布时间】:2015-10-21 16:28:02
【问题描述】:

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

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&lt;T, char&gt; 必须是 is_same&lt;U, char&gt;

【问题讨论】:

  • std::enable_if 是否有效?我原以为失败会很困难,因为 T 不在函数声明的直接上下文中。
  • 你完全正确,在这种情况下 is_same 必须是 is_same

标签: c++ c++11 c++builder-xe visual-c++-2013


【解决方案1】:

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

其次,如果你不想使用 enable_if,你可以简单地为 w_char 提供一个 myString 的特化。为了减少编码量,把它放在某个基类中,从基类派生出myString,并提供基类的特化。

【讨论】:

    【解决方案2】:

    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 之前的 C++ 中可以正常工作。

    【讨论】:

      【解决方案3】:

      首先,您的 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);
      

      【讨论】:

      • @Christian 等等,那是一个完全不同的问题。现在你甚至根本不需要enable_if...
      • 我需要enable_if_t&lt;&gt;,如果专业是HGStringBasic&lt;wchar_t&gt;,那么我有一个operator += (const wchar_t*),第二个运算符是operator += (const char*)。但是如果特化是 HGStringBasic,则不会使用第二个运算符,因为 operator += (const char*) 的第一个实现。所以如果特化是 HGStringBasic&lt;wchar_t&gt;,我可以将 const char* 附加到我的字符串。
      【解决方案4】:

      现在我已经弄清楚了,没有 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;
              }
      };
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2020-05-30
        • 1970-01-01
        • 2012-10-01
        • 2016-01-23
        • 2011-05-08
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多