MATLAB arrays support matrix operations and element operations. For example, M*N and M.*N. This is a quite intuitive way to distinguish the two different operations. If I want to implement similar operations in C++, how can I do that?
Can I create a new operator, .*, too? If yes, can anyone give me some guidance?
8 Answers
Answers 1
No, you can't overload op.*:
[C++03 & C++11: 13.5/3]:The following operators cannot be overloaded:. .* :: ?:
Answers 2
You cannot overload .* (see Lightness' answer for standard text), but, interestingly enough, you can overload ->* (similar to how you can overload -> but not .). If that's sufficient for differentiation, then have at it:
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'; } That'll print Int(30), Int(11).
Answers 3
In C++, there's a list of predefined operators, most of which are overloadable (.* is not). Additionally, any name can be used as an operator like:
#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); } Disclaimer: This, strictly speaking, gets translated to (5 < myop) > 2, which is LHSlt<int, decltype(myop)>(5) > 2. Thus it's not a new 'operator', in C++-terms, but it's used exactly the same way, even in terms of ADL. Also, if type is large, you probably want to store const T&.
Note that you can do this with any binary operator that can be defined external to the class; precedence is based on the precedence of the two sides (< and >). Thus you can have e.g. *myop*, +myop+, <<myop>>, <myop>, |myop| in this order of precedence.
If you want right-associativity, it gets a bit more tricky. You'll need both of a RHS-holder and LHS-holder (the latter being LHSlt here) and use surrounding operators such that the right one has higher precedence than the left one, e.g. a |myop> b |myop>c is a |myop> (b |myop> c). Then you need the function for both your type and your holder type as the lhs.
Answers 4
No, unfortunately you cannot define new operators--you can only overload existing operators (with a few important exceptions, such as operator.). Even then, it's typically only a good idea to overload operators for types which have very clear and uncontroversial existing semantics for a given operator--for instance, any type that behaves as a number is a good candidate for overloading the arithmetic and comparison operators, but you should make sure that operator+ doesn't, say, subtract two numbers.
Answers 5
MATLAB arrays support matrix operations and element operations. For example, M*N and M.*N. This is a quite intuitive way to distinguish the two different operations. If I want to implement similar operations in C++, how can I do that?
Can I create a new operator, .*, too? If yes, can anyone give me some guidance?
As for the first part you can overload most of the operators and there are some that you can not overload and the list of operators in C++ are:
Arithmetic
+ (addition)- (subtraction)* (multiplication)/ (division)% (modulus)
Bitwise
^ (XOR)| (OR)& (AND)~ (Complement)<< (Shift Left, Insertion to Stream)>> (Shift Right, Extraction from Stream)
Assignment
= (Assignment)
Relational
== (Equality)!= (Inequality)> (Greater-Than)< (Less-Than)>= (Greater-Than Or Equal-To)<= (Less-Than Or Equal-To)
Logical
! (NOT)&& (AND)|| (OR)
Compound Assignment
+= (Addition-Assignment)-= (Subtraction-Assignment)*= (Multiplication-Assignment)/= (Division-Assignment)%= (Modulus-Assignment)&= (AND-Assignment)|= (OR-Assignment)^= (XOR-Assignment)<<= (Shift-Left Assignment)>>= (Shift-Right Assignment)
Increment - Decrement - Both have 2 forms (prefix) and (postfix)
++ (Increment)-- (Decrement)
Subscript
[] (Subscript)
Function Call
() (Function Call)
Address, Reference, Pointer
operator&()operator*()operator->()
Comma
operator,()
Member Reference
operator->()operator->*()
Memory Management
newdeletenew[]delete[]
Conversion
operator "type" () const
NON Modifiable Operators - Operators that can not be overloaded
?: (Conditional - Ternary). (Member Selection).* (Member Selection With Pointer To Member):: (Scope Resolution)sizeof() (Object Size Information)typeid() (Object Type Information)
So knowing this list will help to answer your questions. Can you Create a "New Operator" in C++? No! If you want to implement similar operations in C++; how can I do that?
You have 4 choices: Either overload an already existing operator that can be overloaded, write a function or method to do the type of calculations you want to perform, create a template type to do the work for you, or the last one which is the least common to do but you can also write macros to do them for you.
There is a header only Math API Library that is used quite frequently with OpenGL graphics API and OpenGL's Shader Language GLSL and this library has many features that work with vectors, matrices, quaternions etc., and all the necessary functions and operations that can be done to them. Here is the link to GLM You can have a look at their documentation as well as their library implementations since it is a headers only library or API. This should give you some insight on how they constructed their Vector and Matrix objects and the operations that can be done to them.
Answers 6
BTW: I am seeking to answer the parts of this question as asked. I am also not seeking to replicate all the information in other worthy answers. The bounty seeks something different to the question as asked, so I am not responding to that.
It is actually fairly simple to provide a matrix multiplication. Since I'm not proposing to describe data structures to represent a matrix and fully implement operations and validity checks on them, I'll just provide skeletons to illustrate.
Example 1: operator*() as a member function
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 } The above implements operator*() as a member function. So, functionally, c = a*b is equivalent to c = a.operator*(b). The const qualifiers represent the fact that a matrix multiplication a*b does not generally change a or b.
Example 2: operator*() as a non-member function
Now, operator*() can also be implemented as a non-member (optionally a friend), with a skeleton that looks like
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 Note that, in this case, a*b is now equivalent to operator*(a, b).
If you want to use both forms, care is needed to avoid ambiguity. If both forms of operator*() are provided they are both valid matches in a statement like c = a*b and the compiler has no means to choose one form over the other. The result is code not compiling.
Example 3: overloading operator*()
It is also possible to overload operator*() - for example, to multiply a matrix by a scalar.
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 } In the above b*2.0 amounts to a call of b.operator*(2.0) and 2.0*a to a call of the non-member operator*(2.0, a). The member forms can only generally be used in expressions where the left hand operand is of type M. So 2.0*a will not work if only member forms of operator*() is provided.
Discussion
Apart from concerns of ambiguity above, there are other things to be aware of when overloading operators.
- It is not possible to change precedence or associativity of operators from their specification in language rules. So, in the expression
a+b*c, the*will always have higher precedence than the+. This is also the reason it is not a good idea to overload^for exponentiation in C++, since^has a lower precedence than+in C++ (being a bitwise operation on integral types). Soa + b^cis actually equivalent in C++ to(a + b)^c, not toa + (b^c)(which anyone with basic knowledge of algebra would expect). - The language specifies a set of operators, and it is not possible to create new ones. For example, there is no
**in C++, such thata ** braisesato the power ofb(which other languages can do), and it is not possible to create one. - Not all operators can be overloaded.
One of the operators that cannot be overloaded in C++ is .*. So it is not possible to use such an operator like you would in Matlab. I would generally suggest NOT trying to get the same effect using other operators, because the above constraints will affect that (and cause expressions to give counter-intuitive behaviour). Instead simply provide another named function to do the job. For example, as a member function
class M { public: // other stuff M ElementWiseProduct(const M &) const; }; Answers 7
It's as simple (and as difficult!) as defining a function named (in this case) operator*():
Matrix operator*(const Matrix &m1, const Matrix &m2) ... where Matrix is a class you've defined to represent matrices.
Answers 8
As other answers say, overloading operator.* is not possible.
But I got a good solution for your question, check here.
You can provide any methods in operator-ish form like:
M <matrix_mul> N
0 comments:
Post a Comment