避免模​​板化运算符重载的隐式参数转换

Avoid implicit argument conversion of templated operator overload

我的问题是,如何防止显示的行为,但正如 Cheersandhth.-Alf 指出的那样,我没有包含导致此问题的构造函数。 现在包含构造函数,很明显,将浮点数(以及其他任何内容)转发给 std::array ctor 导致了这个问题。

我仍然希望能够使用这种初始化方式Vec2 a = {1.f, 2.f},但是转发 ctor 非常危险,所以我会避免它。

我有一个从 std::array 派生的 Vec class,它应该通过运算符重载实现通常的组件式算术运算。应该为相同类型和大小的其他 Vec(在这种情况下对相应的向量分量进行操作)以及整数和浮点类型实现运算符。

例如

{1.f, 2.f, 3.f} * 2.f = {2.f, 4.f, 6.f}
{1.f, 0.f} + {0.f, 1.f} = {1.f, 1.f}

这是我所做的(仅显示给操作员*)https://godbolt.org/g/PtCkzR:

template<class T, size_t N>
class Vec : public std::array<T, N>
{
public:
  template<typename... S>
  Vec(S&&... params) : std::array<T, N>{std::forward<S>(params)...} { };

  friend Vec<T, N>& operator*=(Vec<T, N>& a, const Vec<T, N>& b)
  {
    std::transform(a.begin(), a.end(), b.begin(), a.begin(), std::multiplies<>());
    return a;
  }

  template<class S>
  friend Vec<T, N>& operator*=(Vec<T, N>& a, const S& b)
  {
    std::transform(a.begin(), a.end(), a.begin(), [&] (T x) { return x*b; });
    return a;
  }

  template<class S>
  friend Vec<T, N> operator*(Vec<T, N> a, const S& b)
  {
    return a *= b;
  }
};
using Vec2 = Vec<float, 2>;

现在,当我想将一个向量与一个浮点数相乘时,会发生这种情况:

Vec2 a{1.f, 1.f};
auto b = a * 0.5f; // b = {.5f, .5f} <- as expected
auto c = 0.5f * a; // c = {.5f, 0.f} <- what happened here?

发生这种情况是因为第三行中的 0.5f 被隐式转换为 Vec2 {0.5f, 0.f},然后传递给 operator*(Vec2, const Vec2&) 重载。

添加另一个 operator* 重载函数,其中 LHS 可以是数字。

template<class S>
   friend Vec<T, N> operator*(S b, Vec<T, N> a)
   {
      return a *= b;
   }