加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

c – 如何模拟一组相关类的运算符重载而不与标准库运算符冲突?

发布时间:2020-12-16 10:13:35 所属栏目:百科 来源:网络整理
导读:这似乎是一个相当直接的想法:我有一组类,我应该能够编写一个运算符,让我们说减法,基本上使用完全相同的代码. 试图以“明显”的方式做到这一点时,即: template typename TT operator-(T a,const T b) { return a -= b;} 然后,在某些编译器上,这似乎与迭代器
这似乎是一个相当直接的想法:我有一组类,我应该能够编写一个运算符,让我们说减法,基本上使用完全相同的代码.

试图以“明显”的方式做到这一点时,即:

template <typename T>
T operator-(T a,const T& b) {
    return a -= b;
}

然后,在某些编译器上,这似乎与迭代器的减法运算符冲突(特别是它在gcc 3.4.6和Apple LLVM上打破,虽然看起来在gcc版本4或更新版本上正常工作),但是我收到以下错误:

error: use of overloaded operator '-' is ambiguous (with operand types 'std::__1::__wrap_iter<const double *>' and 'const_iterator'
      (aka '__wrap_iter<const_pointer>'))

我还考虑了模板重载只是一个基类,从中可以派生出组中的所有类,但是由于第一个参数是按值传递的,我认为特定于子类的信息在复制期间会丢失.

我错过了一些明显的东西吗有没有办法让所有这些编译器都满意?

编辑:理想情况下,解决方案应该在C 03中工作.

解决方法

使用基类,adl koenig运算符和sfinae.

namespace ops{
  struct subtract_support{
    template<class T,std::enable_if_t<std::is_base_of<subtract_support,T>{},int> =0
    >
    friend T operator-( T lhs,T const& rhs ){
      lhs-=rhs;
      return lhs;
    }
  };
}

现在继承自ops :: subtract_support会导致 – 适用于您的类型. (注意两行主体:确保lhs移出 –,与OP中的版本不同).

仅仅命名空间限制会导致您找到任何模板生成类型,其中一个tge参数来自您的命名空间,以及其他非预期的情况:adl对模板成员来自特定命名空间的类型进行操作.

这个技巧允许您在声明时将每种类型标记为使用此技术.

这种技术几乎没有二元布局含义.但是如果你需要一些模糊的东西,比如前缀的布局兼容性,则可能需要特征类.

现在,这是一个C 11解决方案.显然OP需要C 03.好吧,最好的方法是像C 11一样实现它,这样在升级编译器时可以删除代码.

enable_if可以很容易地用C 03编写.is_base_of需要多几行:

namespace notstd{
  namespace details{
    template<class T,class U>
    struct base_test{
      typedef char no; // sizeof(1)
      struct yes { no unused[2]; }; // sizeof(2) or greater
      static yes test(T*); // overload if arg is convertible-to-T*
      static no test(...); // only picked if first overload fails
      // pass a `U*` to `test`.  If the result is `yes`,T
      // is a base of U.  Note that inaccessible bases might fail here(?)
      // but we are notstd,good enough.
      enum {value= (
        sizeof(yes)==sizeof(test((U*)0))
      )};
    };
  }
  template<class Base,class T>
  struct is_base_of{
    enum{value=details::base_test<Base,T>::value};
  };
  template<bool b,class T=void>
  struct enable_if {};
  template<class T>
  struct enable_if<true,T> {
    typedef T type;
  };
}

我们还需要在模板ADL运算符中调整SFINAE以符合C 03:

namespace ops{
  struct subtract_support{
    template<class T>
    friend
    typename notstd::enable_if<notstd::is_base_of<subtract_support,T>::value,T>::type
    operator-( T lhs,T const& rhs ){
      lhs-=rhs;
      return lhs;
    }
  };
}

Live example.

1例如,如果Foo是具有贪婪 – 模板运算符的命名空间中的类型,则decltype(v0-v1)其中v0和v1是vector< Foo>将是矢量< Foo>.这是误报(它不会编译).但是vec3< Foo> (具有自己的3 Foo的向量空间)将导致相同的模糊性.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读