| ||||
| Comment on GotW #4 Solution: Class Mechanics by Herb Sutter
@Daryle: I actually did consider whether to talk about making this constexpr, and I deliberately decided not to (and almost mentioned in this in the summary alongside why I didn’t talk about final). Two reasons: (1) I can’t think of any use cases for a compile-time complex number (or any floating point value for that matter); it’s not like we’re going to initialize arrays with them or set enumerator values with them or instantiate templates with them, right? I could be wrong here — does anyone know of a valid constexpr use for a floating point number? (2) Doing it would make this simple class more complicated, as I think you’ve demonstrated. :) And the extra work is for no real advantage (if I’m right about (1)) and with the disadvantage of providing incorrect fodder for people who want to point at examples of how hard simple stuff is in C++, when it isn’t (at least not in this case). I think we should be teaching how simple good code can be, not how complex C++ code can be. This really is simple and doesn’t need constexpr, so I didn’t even mention constexpr. If I’m wrong about that, I’d really be happy to know — what are the use cases for making complex constexpr-aware? If I’m right about that and it’s a FAQ, maybe I should add this kind of note in the Summary along with why I didn’t mention or recommend saying final. Read More »Comment on GotW #4 Solution: Class Mechanics by Michael Marcin
Sorry that was obviously supposed to be: T operator+( const T& lhs, const X& rhs ) { T rv = lhs; rv += rhs; return rv; } Read More » Comment on GotW #4 Solution: Class Mechanics by Michael Marcin
While pass by value for things like operator is good in theory. I’m not sure how good it is in practice. There was recently talk about this related to the boost operators library. Compare T operator+( T lhs, const X& rhs ) { lhs += rhs; return lhs; } T operator+( const T& lhs, const X& rhs ) { T rv = lhs; rv += lhs; return rv; } Read More » Comment on GotW #4 Solution: Class Mechanics by Róbert Dávid
@Daryle Walker: I’m not sure it is a good idea to use range-for on a.. single.. complex value. @Herb Sutter: Compile-time float values is something I would kill for while implementing code from mathematicians, containing code that is essentially possible to do compile time – but it is not feasible to just code the ‘result’ into the code, as the constant changing every iteration. To oversimplify, something like “return input*2*sqrt(3)” at first, “return input*3*sqrt(3)” in the second version, “return input*3*sqrt(5)” in the third (mixed with changes of ‘non-compile-time’ logic as well). And this happened in three companies so far, so I have a sense that this isn’t really uncommon. Generally, I would like to push as much computation to compile time as possible – constexpr can do miracles, even with its current, limited version. (constexpr dgemm, anyone?) Read More »Comment on GotW #4 Solution: Class Mechanics by nosenseetal
can somebody explain what Herb meant with this: ” That makes the class annoying to use at all.” Read More »Comment on GotW #5: Overriding Virtual Functions by Pavel Davydov
1. override means that this function should override some virtual function from the parent class. final means that this function should not be overridden in some child class. class base { public: virtual void f( int ) final; //if function is not meant to be overridden, it should be final virtual void f( double ) final; virtual void g( int i ); //avoid using default values in virtual functions, they are chosen statically virtual void g( ); //use separate virtual function without arguments instead virtual ~base() {} }; void base::g( ) { g(10); } class derived: public base { public: using base::f; //to make f functions from base visible here void f( complex<double> ); void g( int i ) override; //override makes the compiler check if this function really override something void g( ) override; }; void derived::g( ) { g(20); } 2. b) the actual result of execution is: b.f(1.0); //base::f d.f(1.0); //derived::f( complex<double> ), expected base::f( double ) pb->f(1.0); //base::f b.g(); //10 d.g(); //20 pb->g(); //10 cause defaults are chosen statically, expected 20Read More » Comment on GotW #4 Solution: Class Mechanics by Daryle Walker
@Herb Sutter (2013-5-21T10:59): I’ve heard about transcendental functions being implemented with the help of internal constant tables. Constexpr can help there. A response by Róbert Dávid described something similar. The constexpr is also a just-in-case some programmer changes complex to a class template, like the “value_type” alias added. (Like if we want “int” versions. There’s no reason for complex to be limited to floating-point; anything besides division, “abs,” and the transcendentals works just fine with integer arithmetic.) What the haters don’t see is that “superfluous” code isn’t over-engineering basic stuff, but adding the finishing details. They’re refinements. Middle programmers have to worry about those details and do a pass beyond make-it-work so they don’t pass inefficiencies down the line. Maybe you can do a GotW on constexpr someday. @Róbert Dávid (2013-5-21T12:22): Yes, it could be considered overkill, but complex range-for support may come in handy for generic code. The tuple support is another example. Read More »Comment on GotW #2 Solution: Temporary Objects by GeoffW
A question about the short string optimisation comments made in this article. You say that “SSO is a wonderful optimization”, but offer no references in support of this. Are there articles around that demonstrate the advantages of SSO in a realistic manner? I mean SSO looks good in theory, but so does copy-on-write. Is it proven to be worth blowing out the size of a string object from a single pointer to something that is some multiple of that just to implement SSO? In particular I am wondering if the perceived advantages of SSO may be less as more code takes advantage of C++11 move semantics in their interfaces. Read More »Comment on GotW #4 Solution: Class Mechanics by Matthew Fioravante
@Herb: When it comes to value types however, there are no move semantics so the optimization game we’re trying to play here is copy ellision in either one of the parameters or the return value. The problem is that with passing one of the parameters by value is that the optimization only works if the caller happens to use an rvalue for that parameter (5 + x) vs (x + 5). For something like operator+(), we always use the return value so copy ellision can always be taken advantage of if its done on the return side vs on the parameter side. This could matter for a math library such a 3d linear algebra library for a game engine where you are doing a lot of 4×4 matrix multiplies. Theres also the minor issue that the copy for passing by value is done at every call site and possibly bloats the code if the function is called often. Also when passing by value, which argument should be a reference and which a value? T operator+(const T& a, T b); T operator+(T a, const T& b); Should we pick a convention and suggest everyone follow it? Much like preferring ++i to i++ with iterators? I often find myself writing x + 5, than I do 5 + x. If your type has move semantics then the most correct way to do it is with a bunch of ugly overloads. T operator+(const T& a, const T& b); T operator+(const T& a, T&& b); T operator+(T&& a, const T& b); T operator+(T&& a, T&& b); Perhaps the following: T operator+(const T& a, const T& b) { T c = a; //this one must do a copy c += b; return c; } T operator+(const T& a, T&& b) { T c = std::move(b); //great, we can move c += a; return c; } T operator+(T&& a, const T& b) { return b + std::move(a); //calls lv + rv } T operator+(T&& a, T&& b) { return a + std::move(b); //calls lv + rv } Or this? (Does this even work like the above in all cases?) T operator+(T a, const T& b) { return a += b; //lv + lv or rv + lv } T operator+(const T& a, T&& b) { return std::move(b) + a; //calls rv + lv } T operator+(T&& a, T&& b) { return std::move(a) + b; //calls rv + lv } Read More » Comment on GotW #4 Solution: Class Mechanics by Herb Sutter
@Matthew: Yes, there will eventually be another GotW on parameter passing that will cover these kinds of things. Read More »Comment on GotW #3 Solution: Using the Standard Library (or, Temporaries Revisited) by David Collier
Sorry for the digression, but from that concepts@isocpp thread it seems a big part of the objections is the ambiguity whereby [](e) { … } could mean a function taking an unnamed parameter of type e. Which looks like a fair point. I was wondering whether it had been considered to have a specific exception for ref and const-ref parameters, so that you could write [](&e) { use(e) } but if you wanted pass-by-value, or if you wanted something more complicated like a parameter of type function-taking-auto-returning-bool, you’d have to use the auto placeholder. I’d have thought that reference parameters are more useful than by-value parameters in a generic context, so this doesn’t seem to lose much. Read More » | ||||
| ||||
Wednesday, May 22, 2013
FeedaMail: Comments for Sutterâs Mill
Subscribe to:
Post Comments (Atom)
No comments:
Post a Comment