【发布时间】:2018-02-14 19:54:04
【问题描述】:
我的问题是,如何防止显示的行为,但正如 Cheersandhth.-Alf 指出的那样,我没有包含导致此问题的构造函数。 现在包含构造函数,很明显,将浮点数(以及其他任何内容)转发到 std::array ctor 会导致此问题。
我仍然希望能够使用这种初始化Vec2 a = {1.f, 2.f},但是转发 ctor 非常危险,所以我会避免这种情况。
我有一个从 std::array 派生的 Vec 类,它应该通过运算符重载实现通常的组件式算术运算。运算符应针对相同类型和大小的其他 Vecs(在这种情况下对相应的向量分量进行操作)以及整数和浮点类型实现。
例如
{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&) 重载。
【问题讨论】:
-
你有
friend Vec<T, N> operator*(Vec<T, N> a, const S& b),也写friend Vec<T, N> operator*(const S& b, Vec<T, N> a),这应该可以解决你的问题。 -
您应该将乘法运算符设为非模板
operator*(Vec<T, N> a, const T& b)并提供将标量作为第一个参数的变体operator*(const T& b, Vec<T, N> a)。 -
OT:我强烈建议您不要从
std::array继承,而是将其用作成员变量。 组合优于继承 -
"我真的必须为 Vec2 op S 和 S op Vec2 实现所有模板化运算符函数一次吗?"是我在底部问的。那么就没有别的办法了吗?我认为将这些运算符实现为友元函数或在类之外实现是避免额外代码的方法。
-
@eike 是的。
标签: c++ templates operator-overloading implicit-conversion