digitalmars.D - C++ overloaded operators and D
- IgorStepanov (37/37) Nov 11 2014 Now D provides very powerfull means to link C++ code with D.
- deadalnix (3/42) Nov 11 2014 Why would you want to go that road ? Souldn't extern(C++) struct
- IgorStepanov (12/61) Nov 12 2014 C++ and D provides different behaviour for operator overloading.
- "Marc =?UTF-8?B?U2Now7x0eiI=?= <schuetzm gmx.net> (12/25) Nov 12 2014 operator[] can be mapped to opIndex just fine, right? Only
- IgorStepanov (45/72) Nov 12 2014 opBinary(Right) is a template-functions. You can't add previous
- "Marc =?UTF-8?B?U2Now7x0eiI=?= <schuetzm gmx.net> (4/53) Nov 12 2014 I see...
- IgorStepanov (4/63) Nov 12 2014 What if
- "Marc =?UTF-8?B?U2Now7x0eiI=?= <schuetzm gmx.net> (6/73) Nov 13 2014 For a C++ class interfaced from D: opBinary() in whichever of the
- IgorStepanov (12/86) Nov 13 2014 It is too difficult, I think.
Now D provides very powerfull means to link C++ code with D. However D doesn't allow to call C++ overloaded operators. It's very annoying, because C++ code may don't provide non-operator analogues. What we know about C++ overloadable operators? Overloaded operator in C++ is a trivial function/method with special name. Thus operator[](int) differs from op_index(int) function only by mangle. C++ OO have a different behaviour from D OO (for example C++ allows different < and > operator overloads or static function fro binary operators), thus we should avoud the temptation of map C++ OOs to D OOs, or back. Also D provides a pragma(mangle) which allows to redefine symbol mangle. It takes a string argument and redefine mangle to it: pragma(mangle, "foo") void bar();//bar.mangleof == foo I suggest to modify pragma(mangle) to support C++ operators. If argument of this pragma is identifier (for example cppOpAdd), the pragma applied to extern(C++) function or method, compiler mangle the function in accordance with this identifier. //C++ struct Foo { int& operator[](int); //another fields }; //D extern(C++) struct Foo { pragma(mangle, cppOpIndex) ref int op_index(int); //another fields } //using: Foo f; f.op_index(1)++; //OK, op_index is linked with Foo::operator[] f[1]++; //Error, no special behaviour for op_index I think this approach is simple, doesn't modify the language, can be easily implemented and usefull. Destroy!
Nov 11 2014
On Tuesday, 11 November 2014 at 22:26:48 UTC, IgorStepanov wrote:Now D provides very powerfull means to link C++ code with D. However D doesn't allow to call C++ overloaded operators. It's very annoying, because C++ code may don't provide non-operator analogues. What we know about C++ overloadable operators? Overloaded operator in C++ is a trivial function/method with special name. Thus operator[](int) differs from op_index(int) function only by mangle. C++ OO have a different behaviour from D OO (for example C++ allows different < and > operator overloads or static function fro binary operators), thus we should avoud the temptation of map C++ OOs to D OOs, or back. Also D provides a pragma(mangle) which allows to redefine symbol mangle. It takes a string argument and redefine mangle to it: pragma(mangle, "foo") void bar();//bar.mangleof == foo I suggest to modify pragma(mangle) to support C++ operators. If argument of this pragma is identifier (for example cppOpAdd), the pragma applied to extern(C++) function or method, compiler mangle the function in accordance with this identifier. //C++ struct Foo { int& operator[](int); //another fields }; //D extern(C++) struct Foo { pragma(mangle, cppOpIndex) ref int op_index(int); //another fields } //using: Foo f; f.op_index(1)++; //OK, op_index is linked with Foo::operator[] f[1]++; //Error, no special behaviour for op_index I think this approach is simple, doesn't modify the language, can be easily implemented and usefull. Destroy!Why would you want to go that road ? Souldn't extern(C++) struct mangle this the right way by themselves ?
Nov 11 2014
On Wednesday, 12 November 2014 at 02:37:52 UTC, deadalnix wrote:On Tuesday, 11 November 2014 at 22:26:48 UTC, IgorStepanov wrote:C++ and D provides different behaviour for operator overloading. D has a opIndex + opIndexAssign overloads, and if we want to map opIndex to operator[], we must to do something with opIndexAssign. operator< and operator> can't be mapped to D. Same for operator&. Binary arithmetic operators can't be mapped to D, if them implemented as static functions: Foo operator+(int a, Foo f); //unable to map it to D, because static module-level Foo opAdd(int, Foo) will not provide the same behaviour as operator+ in D. Thus: C++ and D overloaded operators should live in different worlds.Now D provides very powerfull means to link C++ code with D. However D doesn't allow to call C++ overloaded operators. It's very annoying, because C++ code may don't provide non-operator analogues. What we know about C++ overloadable operators? Overloaded operator in C++ is a trivial function/method with special name. Thus operator[](int) differs from op_index(int) function only by mangle. C++ OO have a different behaviour from D OO (for example C++ allows different < and > operator overloads or static function fro binary operators), thus we should avoud the temptation of map C++ OOs to D OOs, or back. Also D provides a pragma(mangle) which allows to redefine symbol mangle. It takes a string argument and redefine mangle to it: pragma(mangle, "foo") void bar();//bar.mangleof == foo I suggest to modify pragma(mangle) to support C++ operators. If argument of this pragma is identifier (for example cppOpAdd), the pragma applied to extern(C++) function or method, compiler mangle the function in accordance with this identifier. //C++ struct Foo { int& operator[](int); //another fields }; //D extern(C++) struct Foo { pragma(mangle, cppOpIndex) ref int op_index(int); //another fields } //using: Foo f; f.op_index(1)++; //OK, op_index is linked with Foo::operator[] f[1]++; //Error, no special behaviour for op_index I think this approach is simple, doesn't modify the language, can be easily implemented and usefull. Destroy!Why would you want to go that road ? Souldn't extern(C++) struct mangle this the right way by themselves ?
Nov 12 2014
On Wednesday, 12 November 2014 at 11:43:36 UTC, IgorStepanov wrote:C++ and D provides different behaviour for operator overloading. D has a opIndex + opIndexAssign overloads, and if we want to map opIndex to operator[], we must to do something with opIndexAssign.operator[] can be mapped to opIndex just fine, right? Only opIndexAssign wouldn't be accessible from C++ via an operator, but that's because the feature doesn't exist. We can still call it via its name opIndexAssign.operator< and operator> can't be mapped to D. Same for operator&.That's true. Maybe we can just live with pragma(mangle) for them, but use D's op... for all others?Binary arithmetic operators can't be mapped to D, if them implemented as static functions: Foo operator+(int a, Foo f); //unable to map it to D, because static module-level Foo opAdd(int, Foo) will not provide the same behaviour as operator+ in D. Thus: C++ and D overloaded operators should live in different worlds.Can't we map both static and member operators to opBinary resp. opBinaryRight members in this case? How likely is it that both are defined on the C++ side, and if they are, how likely is it that they will behave differently?
Nov 12 2014
On Wednesday, 12 November 2014 at 14:41:17 UTC, Marc Schütz wrote:On Wednesday, 12 November 2014 at 11:43:36 UTC, IgorStepanov wrote:opBinary(Right) is a template-functions. You can't add previous declaration for it to struct: //C++ struct Foo { Foo operator+(const Foo&); }; Foo operator+(int, const Foo&); //D extern(C++) struct struct Foo { Foo opBinary!"+"(const ref Foo); //??? } Foo opBinary!"+"(int, const ref Foo); //??? May be some cases can be mapped to D, but these cases require special consideration. I suggest a generic rule. extern(C++) struct struct Foo { pragma(mangle, cppOpAdd)Foo op_add(const ref Foo); } extern(C++) pragma(mangle, cppOpAdd)Foo op_add2(int, const ref Foo); Now, if you want to use this overloaded operators as D operators, you may wrap it to D operator-functions. extern(C++) struct struct Foo { pragma(mangle, cppOpAdd) Foo op_add(const ref Foo); Foo opBinary(string s)(const ref Foo rvl) if (s == "+") { return op_add(rvl); } Foo opBinaryRight(string s)(int lvl) if (s == "+") { return op_add2(lvl, this); } } extern(C++) pragma(mangle, cppOpAdd)Foo op_add2(int, const ref Foo); This way allows access to C++ operators and doesn't add new rules into the language.C++ and D provides different behaviour for operator overloading. D has a opIndex + opIndexAssign overloads, and if we want to map opIndex to operator[], we must to do something with opIndexAssign.operator[] can be mapped to opIndex just fine, right? Only opIndexAssign wouldn't be accessible from C++ via an operator, but that's because the feature doesn't exist. We can still call it via its name opIndexAssign.operator< and operator> can't be mapped to D. Same for operator&.That's true. Maybe we can just live with pragma(mangle) for them, but use D's op... for all others?Binary arithmetic operators can't be mapped to D, if them implemented as static functions: Foo operator+(int a, Foo f); //unable to map it to D, because static module-level Foo opAdd(int, Foo) will not provide the same behaviour as operator+ in D. Thus: C++ and D overloaded operators should live in different worlds.Can't we map both static and member operators to opBinary resp. opBinaryRight members in this case? How likely is it that both are defined on the C++ side, and if they are, how likely is it that they will behave differently?
Nov 12 2014
On Wednesday, 12 November 2014 at 19:32:32 UTC, IgorStepanov wrote:On Wednesday, 12 November 2014 at 14:41:17 UTC, Marc Schütz wrote:I see...On Wednesday, 12 November 2014 at 11:43:36 UTC, IgorStepanov wrote:opBinary(Right) is a template-functions. You can't add previous declaration for it to struct: //C++ struct Foo { Foo operator+(const Foo&); }; Foo operator+(int, const Foo&); //D extern(C++) struct struct Foo { Foo opBinary!"+"(const ref Foo); //???C++ and D provides different behaviour for operator overloading. D has a opIndex + opIndexAssign overloads, and if we want to map opIndex to operator[], we must to do something with opIndexAssign.operator[] can be mapped to opIndex just fine, right? Only opIndexAssign wouldn't be accessible from C++ via an operator, but that's because the feature doesn't exist. We can still call it via its name opIndexAssign.operator< and operator> can't be mapped to D. Same for operator&.That's true. Maybe we can just live with pragma(mangle) for them, but use D's op... for all others?Binary arithmetic operators can't be mapped to D, if them implemented as static functions: Foo operator+(int a, Foo f); //unable to map it to D, because static module-level Foo opAdd(int, Foo) will not provide the same behaviour as operator+ in D. Thus: C++ and D overloaded operators should live in different worlds.Can't we map both static and member operators to opBinary resp. opBinaryRight members in this case? How likely is it that both are defined on the C++ side, and if they are, how likely is it that they will behave differently?} Foo opBinary!"+"(int, const ref Foo); //???But this would of course be opBinaryRight, and inside struct Foo.
Nov 12 2014
On Wednesday, 12 November 2014 at 20:49:42 UTC, Marc Schütz wrote:On Wednesday, 12 November 2014 at 19:32:32 UTC, IgorStepanov wrote:What if Foo operator+(const Bar&, const Foo&);? Is it Foo.opBinaryRight, or Bar.opBinary, or both?On Wednesday, 12 November 2014 at 14:41:17 UTC, Marc Schütz wrote:I see...On Wednesday, 12 November 2014 at 11:43:36 UTC, IgorStepanov wrote:opBinary(Right) is a template-functions. You can't add previous declaration for it to struct: //C++ struct Foo { Foo operator+(const Foo&); }; Foo operator+(int, const Foo&); //D extern(C++) struct struct Foo { Foo opBinary!"+"(const ref Foo); //???C++ and D provides different behaviour for operator overloading. D has a opIndex + opIndexAssign overloads, and if we want to map opIndex to operator[], we must to do something with opIndexAssign.operator[] can be mapped to opIndex just fine, right? Only opIndexAssign wouldn't be accessible from C++ via an operator, but that's because the feature doesn't exist. We can still call it via its name opIndexAssign.operator< and operator> can't be mapped to D. Same for operator&.That's true. Maybe we can just live with pragma(mangle) for them, but use D's op... for all others?Binary arithmetic operators can't be mapped to D, if them implemented as static functions: Foo operator+(int a, Foo f); //unable to map it to D, because static module-level Foo opAdd(int, Foo) will not provide the same behaviour as operator+ in D. Thus: C++ and D overloaded operators should live in different worlds.Can't we map both static and member operators to opBinary resp. opBinaryRight members in this case? How likely is it that both are defined on the C++ side, and if they are, how likely is it that they will behave differently?} Foo opBinary!"+"(int, const ref Foo); //???But this would of course be opBinaryRight, and inside struct Foo.
Nov 12 2014
On Wednesday, 12 November 2014 at 21:17:42 UTC, IgorStepanov wrote:On Wednesday, 12 November 2014 at 20:49:42 UTC, Marc Schütz wrote:For a C++ class interfaced from D: opBinary() in whichever of the two classes it is defined. For a D class interfaced from C++: choose one, preferably opBinary(), as it's the "natural" one.On Wednesday, 12 November 2014 at 19:32:32 UTC, IgorStepanov wrote:What if Foo operator+(const Bar&, const Foo&);? Is it Foo.opBinaryRight, or Bar.opBinary, or both?On Wednesday, 12 November 2014 at 14:41:17 UTC, Marc Schütz wrote:I see...On Wednesday, 12 November 2014 at 11:43:36 UTC, IgorStepanov wrote:opBinary(Right) is a template-functions. You can't add previous declaration for it to struct: //C++ struct Foo { Foo operator+(const Foo&); }; Foo operator+(int, const Foo&); //D extern(C++) struct struct Foo { Foo opBinary!"+"(const ref Foo); //???C++ and D provides different behaviour for operator overloading. D has a opIndex + opIndexAssign overloads, and if we want to map opIndex to operator[], we must to do something with opIndexAssign.operator[] can be mapped to opIndex just fine, right? Only opIndexAssign wouldn't be accessible from C++ via an operator, but that's because the feature doesn't exist. We can still call it via its name opIndexAssign.operator< and operator> can't be mapped to D. Same for operator&.That's true. Maybe we can just live with pragma(mangle) for them, but use D's op... for all others?Binary arithmetic operators can't be mapped to D, if them implemented as static functions: Foo operator+(int a, Foo f); //unable to map it to D, because static module-level Foo opAdd(int, Foo) will not provide the same behaviour as operator+ in D. Thus: C++ and D overloaded operators should live in different worlds.Can't we map both static and member operators to opBinary resp. opBinaryRight members in this case? How likely is it that both are defined on the C++ side, and if they are, how likely is it that they will behave differently?} Foo opBinary!"+"(int, const ref Foo); //???But this would of course be opBinaryRight, and inside struct Foo.
Nov 13 2014
On Thursday, 13 November 2014 at 09:57:04 UTC, Marc Schütz wrote:On Wednesday, 12 November 2014 at 21:17:42 UTC, IgorStepanov wrote:It is too difficult, I think. 1. Compiler should generate static operator declaration (for linkage with C++) and method-wrapper. 2. We should use old non-template operators (like opAdd, opSub etc.) or introduce new kind of operators. 3. We should explain to the user how to use our operator bindings (explain to the user). Anyway we may implement generic approach with pragma(mangle) now and add special rules for some operators if it be considered usefull. AFAIK, There are many objections aganist operators mapping are mentioned in n.g.On Wednesday, 12 November 2014 at 20:49:42 UTC, Marc Schütz wrote:For a C++ class interfaced from D: opBinary() in whichever of the two classes it is defined. For a D class interfaced from C++: choose one, preferably opBinary(), as it's the "natural" one.On Wednesday, 12 November 2014 at 19:32:32 UTC, IgorStepanov wrote:What if Foo operator+(const Bar&, const Foo&);? Is it Foo.opBinaryRight, or Bar.opBinary, or both?On Wednesday, 12 November 2014 at 14:41:17 UTC, Marc Schütz wrote:I see...On Wednesday, 12 November 2014 at 11:43:36 UTC, IgorStepanov wrote:opBinary(Right) is a template-functions. You can't add previous declaration for it to struct: //C++ struct Foo { Foo operator+(const Foo&); }; Foo operator+(int, const Foo&); //D extern(C++) struct struct Foo { Foo opBinary!"+"(const ref Foo); //???C++ and D provides different behaviour for operator overloading. D has a opIndex + opIndexAssign overloads, and if we want to map opIndex to operator[], we must to do something with opIndexAssign.operator[] can be mapped to opIndex just fine, right? Only opIndexAssign wouldn't be accessible from C++ via an operator, but that's because the feature doesn't exist. We can still call it via its name opIndexAssign.operator< and operator> can't be mapped to D. Same for operator&.That's true. Maybe we can just live with pragma(mangle) for them, but use D's op... for all others?Binary arithmetic operators can't be mapped to D, if them implemented as static functions: Foo operator+(int a, Foo f); //unable to map it to D, because static module-level Foo opAdd(int, Foo) will not provide the same behaviour as operator+ in D. Thus: C++ and D overloaded operators should live in different worlds.Can't we map both static and member operators to opBinary resp. opBinaryRight members in this case? How likely is it that both are defined on the C++ side, and if they are, how likely is it that they will behave differently?} Foo opBinary!"+"(int, const ref Foo); //???But this would of course be opBinaryRight, and inside struct Foo.
Nov 13 2014