MATLAB数组支持矩阵运算和元素运算.例如,M*N
和M.*N
.这是区分两种不同操作的非常直观的方式.如果我想在C++中实现类似的操作,我该怎么做?
我也可以创建一个新的运营商.*
吗?如果是的话,有人可以给我一些指导吗?
Lig*_*ica 27
不,你不能超载op.*
:
[C++03 & C++11: 13.5/3]:
以下运算符不能重载:Run Code Online (Sandbox Code Playgroud). .* :: ?:
lor*_*rro 16
在C++中,有一个预定义运算符列表,其中大多数是可重载的(.*不是).此外,任何名称都可以用作运算符,如:
#include <iostream>
// generic LHSlt holder
template<typename LHS, typename OP>
struct LHSlt {
LHS lhs_;
};
// declare myop as an operator-like construct
enum { myop };
// parse 'lhs <myop' into LHSlt
template<typename LHS>
LHSlt<LHS, decltype(myop)> operator<(const LHS& lhs, decltype(myop))
{
return { lhs };
}
// declare (int <myop> int) -> int
int operator>(LHSlt<int, decltype(myop)> lhsof, int rhs)
{
int& lhs = lhsof.lhs_;
// here comes your actual implementation
return (lhs + rhs) * (lhs - rhs);
}
// strictly optional
#define MYOP <myop>
int main() {
std::cout << (5 <myop> 2) << ' ' << (5 MYOP 2);
}
Run Code Online (Sandbox Code Playgroud)
免责声明:严格地说,被翻译成(5 < myop) > 2
,这是LHSlt<int, decltype(myop)>(5) > 2
.因此,它不是一个新的"运算符",用C++术语来说,但它的使用方式完全相同,即使在ADL方面也是如此.此外,如果类型很大,您可能想要存储const T&
.
请注意,您可以使用可在类外部定义的任何二元运算符执行此操作; 优先级基于双方(<
和>
)的优先级.因此,你可以有例如*myop*
,+myop+
,<<myop>>
,<myop>
,|myop|
在优先顺序.
如果你想要正确的关联性,它会变得有点棘手.你需要一个既RHS持有者和LHS-持有人(后者是LHSlt
在这里),并利用周围的运营商使得右一个具有比左一个更高的优先级,例如a |myop> b |myop>c
是a |myop> (b |myop> c)
.然后你需要你的类型和持有者类型的函数作为lhs.
Bar*_*rry 12
你不能超载.*
(参见Lightness对标准文本的回答),但是,有趣的是,你可以重载->*
(类似于你可以如何重载->
而不是.
).如果这足以区分,那就得到:
struct Int {
int i;
Int operator*(Int rhs) const { return Int{i * rhs.i}; }
Int operator->*(Int rhs) const { return Int{i + rhs.i}; }
friend std::ostream& operator<<(std::ostream& os, Int rhs) {
return os << "Int(" << rhs.i << ')';
}
};
int main() {
Int five{5};
Int six{6};
std::cout << (five * six) << ", " << (five ->* six) << '\n';
}
Run Code Online (Sandbox Code Playgroud)
那打印Int(30), Int(11)
.
MATLAB数组支持矩阵运算和元素运算.例如,M*N和M.*N. 这是区分两种不同操作的非常直观的方式.如果我想在C++中实现类似的操作,我该怎么做?
我可以创建一个新的运算符吗?*?如果是的话,有人可以给我一些指导吗?
至于第一部分,你可以重载大多数运算符,有些你不能重载,C++中的运算符列表是:
算术
+ (addition)
- (subtraction)
* (multiplication)
/ (division)
% (modulus)
按位
^ (XOR)
| (OR)
& (AND)
~ (Complement)
<< (Shift Left, Insertion to Stream)
>> (Shift Right, Extraction from Stream)
分配
= (Assignment)
相关的
== (Equality)
!= (Inequality)
> (Greater-Than)
< (Less-Than)
>= (Greater-Than Or Equal-To)
<= (Less-Than Or Equal-To)
合乎逻辑
! (NOT)
&& (AND)
|| (OR)
复合赋值
+= (Addition-Assignment)
-= (Subtraction-Assignment)
*= (Multiplication-Assignment)
/= (Division-Assignment)
%= (Modulus-Assignment)
&= (AND-Assignment)
|= (OR-Assignment)
^= (XOR-Assignment)
<<= (Shift-Left Assignment)
>>= (Shift-Right Assignment)
增量 - 减少 - 两者都有2种形式(前缀)和(后缀)
++ (Increment)
-- (Decrement)
标
[] (Subscript)
功能调用
() (Function Call)
地址,参考,指针
operator&()
operator*()
operator->()
逗号
operator,()
会员参考
operator->()
operator->*()
内存管理
new
delete
new[]
delete[]
转变
operator "type" () const
不可修改的运算符 - 不能超载的运算符
?: (Conditional - Ternary)
. (Member Selection)
.* (Member Selection With Pointer To Member)
:: (Scope Resolution)
sizeof() (Object Size Information)
typeid() (Object Type Information)
因此,了解此列表将有助于回答您的问题.你能用C++创建一个"新运算符"吗?没有!如果要在C++中实现类似的操作; 我怎样才能做到这一点?
您有4个选择:重载已经存在的可以重载的操作符,编写一个函数或方法来执行您想要执行的计算类型,创建一个模板类型来为您完成工作,或者最后一个是最不常见但你也可以写宏来为你做这些.
有一个标题只有数学API库,经常与OpenGL图形API和OpenGL的着色器语言GLSL一起使用,这个库有许多功能,可以使用向量,矩阵,四元数等,以及可以完成的所有必要的功能和操作给他们.以下是GLM的链接您可以查看他们的文档以及他们的库实现,因为它只是一个头文件库或API.这应该可以让您深入了解它们如何构造Vector和Matrix对象以及可以对它们执行的操作.
不,遗憾的是,您无法定义新的运算符 - 您只能重载现有的运算符(有一些重要的例外,例如operator.
).即便如此,对于给定运算符具有非常清晰且无争议的现有语义的类型,重载运算符通常也是一个好主意 - 例如,任何表示为数字的类型都是重载算术和比较运算符的良好候选者,但是你应该确保operator+
不减去两个数字.
顺便说一句:我正在寻求回答这个问题所提出的部分内容。我也不打算在其他有价值的答案中复制所有信息。赏金寻求与所提出的问题不同的东西,所以我不会对此做出回应。
提供矩阵乘法实际上相当简单。由于我不建议描述数据结构来表示矩阵并完全实现它们的操作和有效性检查,因此我将仅提供框架来说明。
示例1: operator*()
作为成员函数
class M // a basic matrix class
{
public:
// assume other constructors and members to set things up
M operator*(const M &rhs) const;
};
M M::operator*(const M &rhs) const
{
// implement checks on dimensions, throw an exception if invalid
M result;
// implement the multiplication (typical iterations) and store results in result
return result;
}
int main()
{
M a;
M b;
// set up elements of a and b as needed
M c = a*b; // this relies on M having appropriate constructor(s) to copy or move the result of a*b into c
M d;
d = a * b; // this relies on M having appropriate operator=() to assign d to the result of a*b
}
Run Code Online (Sandbox Code Playgroud)
上面operator*()
作为成员函数实现。因此,从功能上来说,c = a*b
相当于c = a.operator*(b)
. 限定符表示矩阵乘法通常不会改变或 的const
事实。a*b
a
b
示例 2: operator*()
作为非成员函数
现在,operator*()
也可以作为非成员(可选friend
)实现,其骨架如下
class M // our basic matrix class, different operator *
{
public:
// assume other constructors and members to set things up
friend M operator*(const M &lhs, const M &rhs);
};
M operator*(const M &lhs, const M &rhs)
{
// implement checks on dimensions, throw an exception if invalid
M result;
// implement the multiplication (typical iterations) and store results in result
return result;
}
// same main() as before
Run Code Online (Sandbox Code Playgroud)
请注意,在这种情况下,a*b
现在相当于operator*(a, b)
.
如果您想使用这两种形式,则需要小心避免歧义。如果提供了两种形式,operator*()
则它们在类似语句中都是有效匹配c = a*b
,并且编译器无法选择一种形式而不是另一种形式。结果是代码无法编译。
示例 3:重载operator*()
也可以重载operator*()
- 例如,将矩阵乘以标量。
class M // a basic matrix class
{
public:
// assume other constructors and members to set things up
M operator*(const M &rhs) const; // as in first example
M operator*(double scalar) const; // member form
friend M operator*(double scalar, const M &rhs); // non-member form
};
M M::operator*(double scalar) const
{
M result;
// implement the multiplication (typical iterations) and store results in result
return result;
}
M operator*(double scalar, const M &m)
{
M result;
// implement the multiplication (typical iterations) and store results in result
return result;
}
int main()
{
M a;
M b;
// set up elements of a and b as needed
M c = b * 2.0; // uses the member form of operator*() above
M d;
d = 2.0*a; // uses the non-member form of operator*() above
}
Run Code Online (Sandbox Code Playgroud)
上面b*2.0
相当于对非会员的呼叫b.operator*(2.0)
和2.0*a
对非会员的呼叫operator*(2.0, a)
。成员形式通常只能用在左侧操作数类型为 的表达式中M
。因此,如果仅提供2.0*a
成员形式,则不起作用。operator*()
讨论
除了上面的歧义问题之外,重载运算符时还需要注意其他事项。
a+b*c
,*
will 的优先级始终高于+
。^
这也是在 C++ 中重载求幂不是一个好主意的原因,因为^
它的优先级比 C++ 低+
(是整数类型的按位运算)。Soa + b^c
在 C++ 中实际上相当于(a + b)^c
,而不是a + (b^c)
(任何具有代数基础知识的人都会期望)。**
这样的a ** b
幂(其他语言可以a
做到b
),并且不可能创建一个。C++ 中不能重载的运算符之一是.*
。所以不可能像在 Matlab 中那样使用这样的运算符。我通常建议不要尝试使用其他运算符获得相同的效果,因为上述约束会影响它(并导致表达式给出反直觉的行为)。相反,只需提供另一个命名函数来完成这项工作。例如,作为成员函数
class M
{
public:
// other stuff
M ElementWiseProduct(const M &) const;
};
Run Code Online (Sandbox Code Playgroud)