简体   繁体   English

如何正确,安全地为std :: array实现C ++算术运算符?

[英]How to correctly and safely implement C++ arithmetic operators for std::array?

I am looking for a correct and safe implementation of C++(17) arithmetic operators for std::array with minimal overhead. 我正在寻找以最小的开销为std :: array正确,安全地实现C ++(17)算术运算符的方法。

In a first attempt, I tried to achieve the above by implementing such operators as non-member functions and by restricting the arguments taken by the operators to arrays with identical arithmetic value_types and of the same size. 我首先尝试通过将此类运算符实现为非成员函数并将运算符采用的参数限制为具有相同算术value_types和相同大小的数组来实现上述目标。 Two examples are given below. 下面给出两个例子。

template< typename T1, std::size_t N1, typename T2, std::size_t N2 >
constexpr inline auto operator-( const std::array< T1, N1 >& lhs, const std::array< T2, N2 >& rhs )
{
  static_assert( std::is_same< T1, T2 >::value );
  static_assert( std::is_arithmetic< T1 >::value );
  static_assert( N1 == N2 );

  std::array< T1, N1 > result;

  for ( std::size_t i = 0; i < N1; ++i )
  {
    result[ i ] = lhs[ i ] - rhs[ i ];
  }

  return result;
}

template< typename T1, std::size_t N1, typename T2, std::size_t N2 >
constexpr inline auto& operator-=( std::array< T1, N1 >& lhs, const std::array< T2, N2 >& rhs )
{
  static_assert( std::is_same< T1, T2 >::value );
  static_assert( std::is_arithmetic< T1 >::value );
  static_assert( N1 == N2 );

  for ( std::size_t i = 0; i < N1; ++i )
  {
    lhs[ i ] -= rhs[ i ];
  }

  return lhs;
}

I would appreciate suggestions to improve the above attempts. 我会建议改善上述尝试的建议。 Especially, I am wondering if the restrictions on the arguments are correct and in case of the minus-operator maybe even too strict? 尤其是,我想知道对参数的限制是否正确,并且如果使用减号运算符,可能会过于严格? Furthermore, I am asking for advice if there is any way to improve the efficiency of the implementations? 此外,我正在征求意见,是否有任何方法可以提高实施效率? That is, is there a better way to conduct the actual arithmetic operations than by the for loops given above? 也就是说,有没有比上面的for循环更好的方法来执行实际的算术运算?

As a general rule, adding non-member operators to a type should be done in the namespace of the type. 通常,应在类型的名称空间中将非成员运算符添加到类型。 Without doing that, your operators won't be found via ADL, and that leads to constant pain. 否则,将无法通过ADL找到您的操作员,这将导致不断的痛苦。

It is not legal to add non-member operators into namespace std . 将非成员运算符添加到namespace std是不合法的。

So the punchline is, don't do this. 所以最重要的是,不要这样做。

Instead, try this: 相反,请尝试以下操作:

template<class T, std::size_t N>
struct vecarray : std::array<T,N> {
  static_assert( std::is_arithmetic< T >::value );
  using std::array<T,N>::array;
  vecarray& operator+=( std::array<T,N> const& rhs )& {
    for (auto& x:*this) {
      x += rhs[ std::addressof(x)- this->data() ];
    }
    return *this;
  }
  vecarray& operator-=( std::array<T,N> const& rhs )& {
    for (auto& x:*this) {
      x -= rhs[ std::addressof(x)- this->data() ];
    }
    return *this;
  }
  vecarray& operator*=( std::array<T,N> const& rhs )& {
    for (auto& x:*this) {
      x *= rhs[ std::addressof(x)- this->data() ];
    }
    return *this;
  }
  vecarray& operator/=( std::array<T,N> const& rhs )& {
    for (auto& x:*this) {
      x /= rhs[ std::addressof(x)- this->data() ];
    }
    return *this;
  }

  friend vecarray operator+( vecarray lhs, std::array<T, N> const& rhs ) {
    lhs += rhs;
    return lhs;
  }
  friend vecarray operator-( vecarray lhs, std::array<T, N> const& rhs ) {
    lhs -= rhs;
    return lhs;
  }
  friend vecarray operator*( vecarray lhs, std::array<T, N> const& rhs ) {
    lhs *= rhs;
    return lhs;
  }
  friend vecarray operator/( vecarray lhs, std::array<T, N> const& rhs ) {
    lhs /= rhs;
    return lhs;
  }
};

this has a whole myriad of improvements over your solution. 与您的解决方案相比,这有很多改进。 Among them, none of the operators are templates, which generates really annoying errors. 其中,运算符都不是模板,它会产生令人讨厌的错误。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM