当 cppreference 说 * 应该作为“对称”的自由函数重载时,“对称”是否意味着交换性?

问题描述 投票:0回答:1

我已经实现了一个类

vec3
:

struct vec3 {
    double x = 0, y = 0, z = 0;
    auto& operator*= (double d) {x *= d; y *= d; z *= d; return *this;}
};

auto operator* (const vec3 &a, double d) {auto ret = a; ret *= d; return ret;}

但是,

vec3{} * 5.
形式的表达式可以编译,而像
5. * vec3{}
这样的表达式则不能编译。这让我很困惑,因为 cppreference 这么说

二元运算符通常被实现为非成员以保持对称性(例如,当将复数和整数相加时,如果operator+是复数类型的成员函数,则只有复数+整数可以编译,而不是整数+ 复杂)。

在这里,我 have 作为非成员实现了

operator*
,所以由于 cppreference 引用中提到的对称性,
vec3{} * 5.
5. * vec3{}
不应该同时编译吗?

c++ c++17 operator-overloading commutativity
1个回答
0
投票

运算符重载的隐式转换对称性

cppreference 所说的“对称”意味着隐式转换的对称。当您将

*
实现为成员函数时,左侧不受用户定义的转换的影响。例如,

    即使
  • vec2::operator*
     可转换为 
    vec3
    ,左侧的 
    vec3
     也无法使用 
    vec2
    成员函数;然而,
  • 如果存在
  • vec2::operator*(vec2)
     转换
    vec3
     仍然可以接受右侧的 
    vec3 -> vec2

这意味着

vec2 * vec3
vec3 * vec2
的工作方式不同,这种不对称性令人惊讶且不受欢迎。 同样,cppreference 示例
complex + integer
的工作方式应与
integer + complex
相同,假设这些是
complex
integer
之间的隐式转换。

可交换运算符重载

您所指的“对称性”是交换性,即交换操作数并为某些操作产生相同结果的能力。默认情况下,C++ 并不使运算符具有可交换性。无论如何,这样做对于大多数人来说都是不安全的,尤其是对于

*
来说。矩阵乘法不可交换,但例如使用
*
符号。

如果你想要交换律,你必须自己做:

auto operator*(const vec3 &a, double d) { auto ret = a; ret *= d; return ret; }
auto operator*(double d, const vec3& a) { return a * d; }

请注意,自 C++20 起,

!=
==
即使在重载时也是可交换的。这是您必须自己定义交换性的规则的一个例外。

© www.soinside.com 2019 - 2024. All rights reserved.