digitalmars.D.learn - const references in C++ and D
- bearophile (65/65) May 30 2010 I am translating a small C++ program to D2 and I am having problems. I a...
- BCS (5/98) May 30 2010 Thats' what I'd do.
- bearophile (4/5) May 30 2010 But wasn't "auto ref" invented for such situations?
- BCS (4/12) May 30 2010 --
- bearophile (4/5) May 31 2010 I don't know what you mean (in that example 3 auto ref doesn't compile, ...
- Trass3r (2/4) May 31 2010 Looks like a compiler bug to me.
- bearophile (19/20) May 31 2010 This doesn't work, I have shown the given error messages in the original...
- Kagamin (1/1) May 31 2010 I think, it's a bug. It was denied to have write access to the temporary...
- bearophile (5/6) May 31 2010 Do you mean the program #3?
- Kagamin (2/7) May 31 2010 I mean program #1
- Trass3r (1/3) May 31 2010 True, there should be an additional check if it's a const ref.
- Steven Schveighoffer (21/94) Jun 01 2010 I've had a long private discussion with Andrei about this problem. C++ ...
- bearophile (5/7) Jun 01 2010 Thank you for your always useful explanations, Steven (this is a fragile...
- Kagamin (3/6) Jun 03 2010 auto ref works only for return values, implementing it for parameters me...
- Steven Schveighoffer (15/24) Jun 03 2010 Using lvalues is just as inefficient as passing temporaries via ref. Th...
- Kagamin (2/4) Jun 03 2010 If the issue is not performance, it shouldn't be mentioned from the star...
- Steven Schveighoffer (7/13) Jun 03 2010 *My* issue is not performance. Andrei's is.
- bearophile (4/5) Jun 03 2010 In most cases seems to work with (input) arguments too.
- Kagamin (2/7) Jun 03 2010 I'm affraid, it works by ignoring auto attribute.
I am translating a small C++ program to D2 and I am having problems. I am learning, but my mind is not large enough for all the subtleties of both C++ and D2 yet :-) This C++ program compiles: struct Vec { void operator+(const Vec& other) {} }; Vec bar(Vec x) { return x; } int main() { Vec() + bar(Vec()); } I think this is the equivalent D2 program: struct Vec { void opBinary(string Op:"+")(const ref Vec other) {} } Vec bar(Vec x) { return x; } void main() { Vec() + bar(Vec()); // line 9 } But DMD gives me: temp3.d(9): Error: function temp3.Vec.opBinary!("+").opBinary (ref const const(Vec) other) is not callable using argument types (Vec) temp3.d(9): Error: bar((Vec())) is not an lvalue I vaguely remember a discussion about this in the D newsgroup, that D acts like this on purpose, so I think this is not a D bug. What is the right way to translate that C++ code to D2? (So far I have just commented out the 'ref' in opBinary). Another case, to me it seems the same problem (D2 code): struct Vec { Vec opOpAssign(string Op:"+=")(ref Vec other) { return this; } Vec opBinary(string Op:"*")(int k) { return this; } } void main() { Vec x; x += Vec() * 2; // line 12 } DMD prints: temp3.d(12): Error: function temp3.Vec.opOpAssign!("+=").opOpAssign (ref Vec other) is not callable using argument types (Vec) temp3.d(12): Error: (Vec()).opBinary(2) is not an lvalue Again I have just commented out the 'ref' here and in most other operator overloading methods. I have seen that in some cases I can use "auto ref" (like in those two examples), but not in all of them, I don't know why. For example here: struct Vec { Vec opOpAssign(string Op)(auto ref Vec other) if (Op == "+=") { return this; } Vec opBinary(string Op:"+")(Vec other) { Vec result; return result += other; } } void main() { Vec v; v += Vec() + Vec(); // line 13 } DMD prints: temp3.d(13): Error: function temp3.Vec.opOpAssign!("+=").opOpAssign (auto ref Vec other) is not callable using argument types (Vec) temp3.d(13): Error: (Vec()).opBinary((Vec())) is not an lvalue Do you know why "auto ref" isn't right here? Bye and thank you, bearophile
May 30 2010
Hello bearophile,I am translating a small C++ program to D2 and I am having problems. I am learning, but my mind is not large enough for all the subtleties of both C++ and D2 yet :-) This C++ program compiles: struct Vec { void operator+(const Vec& other) {} }; Vec bar(Vec x) { return x; } int main() { Vec() + bar(Vec()); } I think this is the equivalent D2 program: struct Vec { void opBinary(string Op:"+")(const ref Vec other) {} } Vec bar(Vec x) { return x; } void main() { Vec() + bar(Vec()); // line 9 } But DMD gives me: temp3.d(9): Error: function temp3.Vec.opBinary!("+").opBinary (ref const const(Vec) other) is not callable using argument types (Vec) temp3.d(9): Error: bar((Vec())) is not an lvalue I vaguely remember a discussion about this in the D newsgroup, that D acts like this on purpose, so I think this is not a D bug.Yes, by design, you can't have a reference to a temporary value.What is the right way to translate that C++ code to D2? (So far I have just commented out the 'ref' in opBinary).Thats' what I'd do.Another case, to me it seems the same problem (D2 code): struct Vec { Vec opOpAssign(string Op:"+=")(ref Vec other) { return this; } Vec opBinary(string Op:"*")(int k) { return this; } } void main() { Vec x; x += Vec() * 2; // line 12 } DMD prints: temp3.d(12): Error: function temp3.Vec.opOpAssign!("+=").opOpAssign (ref Vec other) is not callable using argument types (Vec) temp3.d(12): Error: (Vec()).opBinary(2) is not an lvalue Again I have just commented out the 'ref' here and in most other operator overloading methods. I have seen that in some cases I can use "auto ref" (like in those two examples), but not in all of them, I don't know why. For example here: struct Vec { Vec opOpAssign(string Op)(auto ref Vec other) if (Op == "+=") { return this; } Vec opBinary(string Op:"+")(Vec other) { Vec result; return result += other; } } void main() { Vec v; v += Vec() + Vec(); // line 13 } DMD prints: temp3.d(13): Error: function temp3.Vec.opOpAssign!("+=").opOpAssign (auto ref Vec other) is not callable using argument types (Vec) temp3.d(13): Error: (Vec()).opBinary((Vec())) is not an lvalue Do you know why "auto ref" isn't right here? Bye and thank you, bearophile-- ... <IXOYE><
May 30 2010
BCS:Thats' what I'd do.But wasn't "auto ref" invented for such situations? Bye and thank you, bearophile
May 30 2010
Hello bearophile,BCS:That would work too, assuming that the internals of the function allow it.Thats' what I'd do.But wasn't "auto ref" invented for such situations?Bye and thank you, bearophile-- ... <IXOYE><
May 30 2010
BCS:That would work too, assuming that the internals of the function allow it.I don't know what you mean (in that example 3 auto ref doesn't compile, I don't know if it's a compiler bug or if I am doing something wrong). Bye and thank you, bearophile
May 31 2010
I don't know what you mean (in that example 3 auto ref doesn't compile, I don't know if it's a compiler bug or if I am doing something wrong).Looks like a compiler bug to me. In which cases does it work/doesn't it work?
May 31 2010
Trass3r:In which cases does it work/doesn't it work?This doesn't work, I have shown the given error messages in the original post: struct Vec { Vec opOpAssign(string Op)(auto ref Vec other) if (Op == "+=") { return this; } Vec opBinary(string Op:"+")(Vec other) { Vec result; return result += other; } } void main() { Vec v; v += Vec() + Vec(); // line 13 } It works if you remove "auto ref". I think this is a compiler bug. I will put Bye, bearophile
May 31 2010
I think, it's a bug. It was denied to have write access to the temporary variable, but you request only read access which is safe to be provided.
May 31 2010
Kagamin:I think, it's a bug. It was denied to have write access to the temporary variable, but you request only read access which is safe to be provided.<Thank you for your answers. For me sometimes it's not easy to tell apart my bugs from the compiler bugs. Bye, bearophile
May 31 2010
bearophile Wrote:Kagamin:I think, it's a bug. It was denied to have write access to the temporary variable, but you request only read access which is safe to be provided.<
May 31 2010
I think, it's a bug. It was denied to have write access to the temporary variable, but you request only read access which is safe to be provided.True, there should be an additional check if it's a const ref.
May 31 2010
On Sun, 30 May 2010 19:03:57 -0400, bearophile <bearophileHUGS lycos.com> wrote:I am translating a small C++ program to D2 and I am having problems. I am learning, but my mind is not large enough for all the subtleties of both C++ and D2 yet :-) This C++ program compiles: struct Vec { void operator+(const Vec& other) {} }; Vec bar(Vec x) { return x; } int main() { Vec() + bar(Vec()); } I think this is the equivalent D2 program: struct Vec { void opBinary(string Op:"+")(const ref Vec other) {} } Vec bar(Vec x) { return x; } void main() { Vec() + bar(Vec()); // line 9 } But DMD gives me: temp3.d(9): Error: function temp3.Vec.opBinary!("+").opBinary (ref const const(Vec) other) is not callable using argument types (Vec) temp3.d(9): Error: bar((Vec())) is not an lvalue I vaguely remember a discussion about this in the D newsgroup, that D acts like this on purpose, so I think this is not a D bug. What is the right way to translate that C++ code to D2? (So far I have just commented out the 'ref' in opBinary). Another case, to me it seems the same problem (D2 code): struct Vec { Vec opOpAssign(string Op:"+=")(ref Vec other) { return this; } Vec opBinary(string Op:"*")(int k) { return this; } } void main() { Vec x; x += Vec() * 2; // line 12 } DMD prints: temp3.d(12): Error: function temp3.Vec.opOpAssign!("+=").opOpAssign (ref Vec other) is not callable using argument types (Vec) temp3.d(12): Error: (Vec()).opBinary(2) is not an lvalue Again I have just commented out the 'ref' here and in most other operator overloading methods. I have seen that in some cases I can use "auto ref" (like in those two examples), but not in all of them, I don't know why. For example here: struct Vec { Vec opOpAssign(string Op)(auto ref Vec other) if (Op == "+=") { return this; } Vec opBinary(string Op:"+")(Vec other) { Vec result; return result += other; } } void main() { Vec v; v += Vec() + Vec(); // line 13 } DMD prints: temp3.d(13): Error: function temp3.Vec.opOpAssign!("+=").opOpAssign (auto ref Vec other) is not callable using argument types (Vec) temp3.d(13): Error: (Vec()).opBinary((Vec())) is not an lvalue Do you know why "auto ref" isn't right here?I've had a long private discussion with Andrei about this problem. C++ allows rvalues to be passed into functions that accept const ref. However, it surprisingly is less optimal for rvalues to pass by ref. The reason is because, you must put the temporary on the stack, and then also put the reference on the stack. By simply passing the struct without ref, it's not copied as an lvalue would be, it's simply used where it is, because the compiler knows that it's no longer needed in the calling function. So the optimizer can work more efficiently to remove those extra pushes and pops. In C++, the optimial solution would be to allow the following duplicated methods: foo(const ref Vec); foo(const Vec); as overloads, with the compiler choosing the first for lvalues and the second for rvalues. But you cannot overload based on ref, so this is not allowed. D's solution is to use auto ref, but I think your attempts to use it show that it doesn't work. You should file a bug with your program 3. -Steve
Jun 01 2010
Steven Schveighoffer:D's solution is to use auto ref, but I think your attempts to use it show that it doesn't work. You should file a bug with your program 3.Thank you for your always useful explanations, Steven (this is a fragile bug report, if you change the code a bit the bug vanishes). http://d.puremagic.com/issues/show_bug.cgi?id=4258 Bye, bearophile
Jun 01 2010
Steven Schveighoffer Wrote:However, it surprisingly is less optimal for rvalues to pass by ref.So what? It just must work. Efficiency of a particular operation doesn't mean efficiency of a program: it can use lvalues most of time.D's solution is to use auto ref, but I think your attempts to use it show that it doesn't work. You should file a bug with your program 3.auto ref works only for return values, implementing it for parameters means combinatorial bloat.
Jun 03 2010
On Thu, 03 Jun 2010 09:09:39 -0400, Kagamin <spam here.lot> wrote:Steven Schveighoffer Wrote:Using lvalues is just as inefficient as passing temporaries via ref. The issue is that you can get *better* performance by passing temporaries by value than you can get by passing lvalues by value or by reference. Without something like auto ref, you put achieving the highest performance at odds with usability.However, it surprisingly is less optimal for rvalues to pass by ref.So what? It just must work. Efficiency of a particular operation doesn't mean efficiency of a program: it can use lvalues most of time.At this point, the problem is that there is *nothing* that works for both rvalues and lvalues. auto ref would be something that works, even if it meant duplicating generated code. I personally don't see a huge problem with allowing temporaries to be passed via ref const. It could be a tradeoff between low performance vs. smaller footprint. But Andrei feels very strongly that passing temporaries via const ref is a complete mess in C++, so you'll have to convince him. -SteveD's solution is to use auto ref, but I think your attempts to use it show that it doesn't work. You should file a bug with your program 3.auto ref works only for return values, implementing it for parameters means combinatorial bloat.
Jun 03 2010
Steven Schveighoffer Wrote:But Andrei feels very strongly that passing temporaries via const ref is a complete mess in C++, so you'll have to convince him.If the issue is not performance, it shouldn't be mentioned from the start.
Jun 03 2010
On Thu, 03 Jun 2010 09:47:19 -0400, Kagamin <spam here.lot> wrote:Steven Schveighoffer Wrote:*My* issue is not performance. Andrei's is. I just want something that works. Andrei doesn't want to add some feature that he thinks is a failure in C++. I'm speaking too much for Andrei here, but I think this is the way he feels. -SteveBut Andrei feels very strongly that passing temporaries via const ref is a complete mess in C++, so you'll have to convince him.If the issue is not performance, it shouldn't be mentioned from the start.
Jun 03 2010
Kagamin:auto ref works only for return values,In most cases seems to work with (input) arguments too. Bye, bearophile
Jun 03 2010
bearophile Wrote:Kagamin:I'm affraid, it works by ignoring auto attribute.auto ref works only for return values,In most cases seems to work with (input) arguments too.
Jun 03 2010