Prev: How to test if a iterator is valid or not?
Next: return value optimization vs. returning a boost::shared_ptr of container
From: Paul Bibbings on 14 Jun 2010 23:48 DeMarcus wrote: > Hi, > > I have an object: > > class SomeObject > { > public: > SomeObject(); > > SomeObject& setValue( int i ); > SomeObject& increaseRate( int percent ); > ... etc ... > }; > > This is used in the following manner > > startCalculation( SomeObject().setValue( 47 ).increaseRate( 20 ) ); > > > Now, I want to provide a small wrapper ensuring correct initialization. > My question is; shall I use derivation or a function? I.e. > > struct PreparedObject : SomeObject > { > inline PreparedObject( int i, int percent ) : SomeObject() > { > (*this).setValue( i ).increaseRate( percent ); > } > } > > or shall I use a function: > > inline SomeObject preparedObject( int i, int percent ) > { > return SomeObject().setValue( i ).increaseRate( percent ); > } > > > Later those would be used like this > > startCalculation( PreparedObject( 47, 20 ) ); > > > Both derivation and using a function work, but what are the pros and > cons? What is most elegant, efficient, safe, etc.? Having followed through what you seem to be trying to do here, and supposing that the calls to SomeObject::setValue(int) and SomeObject::increaseRate(int) are not simple initializations (i.e., may involve calculations), then I can't see what any of your ideas gain over the simple: class SomeObject { public: SomeObject(int i, int percent) { setValue(i); increaseRate(percent); } SomeObject& setValue(int i) { // do stuff with i return *this; } SomeObject& increaseRate(int percent) { // do stuff with percent return *this; } private: // ... }; void startCalculation(SomeObject) { } int main() { startCalculation(SomeObject(47, 20)); } If they /are/ just initializations, then use a two-arg constructor and a mem-initializer list. Though not intended to be merely a dig, I have picked up from other similar ideas that you have presented that you have a leaning towards wanting to use chaining at the call site to functions that starts to feel a little `unhealthy' (i.e., counter-productive), especially when you are having to add layers of inheritance, or whatever, just to make it `work'. With respect, you might want to ask yourself if you are doing it differently (i.e., against convention) merely to /be/ different. I can't see how this: startCalculation( SomeObject().setValue( 47 ).increaseRate( 20 ) ); or, especially this: startCalculation( PreparedObject( 47, 20 ) ); can ever achieve anything - *especially* where you are passing a temporary that doesn't exist outside of the call - over: startCalculation(SomeObject(47, 20)); Chaining is `pretty'. It doesn't always *solve* very much. Regards Paul Bibbings -- [ See http://www.gotw.ca/resources/clcm.htm for info about ] [ comp.lang.c++.moderated. First time posters: Do this! ]
From: DeMarcus on 15 Jun 2010 22:56 Goran wrote: > On Jun 15, 11:15 am, DeMarcus <use_my_alias_h...(a)hotmail.com> wrote: >> Hi, >> >> I have an object: >> >> class SomeObject >> { >> public: >> SomeObject(); >> >> SomeObject& setValue( int i ); >> SomeObject& increaseRate( int percent ); >> ... etc ... >> >> }; >> >> This is used in the following manner >> >> startCalculation( SomeObject().setValue( 47 ).increaseRate( 20 ) ); > > I've seen code like this (even wrote some in my time), and I've come > to despise it. The major problem I see with this is that your > modifiers are misleading in form. What they buy is the ability to call > multiple methods on an object in one statement. Uh-oh, big deal. > I'm in a design phase right now and need all input I can get. Can you please explain a bit further; what part is it that you don't like? Is it the function chaining, the temporary object, both, or something else? >> Now, I want to provide a small wrapper ensuring correct initialization. > > Erm... That's what constructor is for? > > On a more general note, it looks like you are using two-step > initialization. In my opinion, there has to be a big fat explanation > for every use. So what's your excuse? ;-) > As Daniel Kr�gler guessed, I'm not allowed to change the constructor of SomeObject, and even if I could, the number of permutations would be gastronomical. One could see SomeObject as a general settings object where the normal use would be startCalculation( SomeObject().setValue( 47 ).increaseRate( 20 ) ); while better compile-time safety could be achieved, forcing some of the optional parameters be mandatory, with wrapper helpers like so startCalculation( PreparedObject( 47, 20 ) ); or even startCalculation( IncreasedRate20( 47 ) ); >> My question is; shall I use derivation or a function? I.e. >> >> struct PreparedObject : SomeObject >> { >> inline PreparedObject( int i, int percent ) : SomeObject() >> { >> (*this).setValue( i ).increaseRate( percent ); >> } >> >> } >> >> or shall I use a function: >> >> inline SomeObject preparedObject( int i, int percent ) >> { >> return SomeObject().setValue( i ).increaseRate( percent ); >> >> } >> >> Later those would be used like this >> >> startCalculation( PreparedObject( 47, 20 ) ); > > If this is __really__ the only way you are happy with :-), I'd say > that a function is better, simply because it's less code artifacts. > (Derivation meant a class and a trivial ctor. That's incidental > complexity, not much more) > A function may seem the obvious choice for most here, but to be picky, will I not get a slight performance hit compared to derivation since I have to return the object? Or will the function inlining take care of that? -- [ See http://www.gotw.ca/resources/clcm.htm for info about ] [ comp.lang.c++.moderated. First time posters: Do this! ]
From: DeMarcus on 15 Jun 2010 22:57 Paul Bibbings wrote: > DeMarcus wrote: >> Hi, >> >> I have an object: >> >> class SomeObject >> { >> public: >> SomeObject(); >> >> SomeObject& setValue( int i ); >> SomeObject& increaseRate( int percent ); >> ... etc ... >> }; >> >> This is used in the following manner >> >> startCalculation( SomeObject().setValue( 47 ).increaseRate( 20 ) ); >> >> >> Now, I want to provide a small wrapper ensuring correct initialization. >> My question is; shall I use derivation or a function? I.e. >> >> struct PreparedObject : SomeObject >> { >> inline PreparedObject( int i, int percent ) : SomeObject() >> { >> (*this).setValue( i ).increaseRate( percent ); >> } >> } >> >> or shall I use a function: >> >> inline SomeObject preparedObject( int i, int percent ) >> { >> return SomeObject().setValue( i ).increaseRate( percent ); >> } >> >> >> Later those would be used like this >> >> startCalculation( PreparedObject( 47, 20 ) ); >> >> >> Both derivation and using a function work, but what are the pros and >> cons? What is most elegant, efficient, safe, etc.? > > Having followed through what you seem to be trying to do here, and supposing > that the calls to SomeObject::setValue(int) and SomeObject::increaseRate(int) > are not simple initializations (i.e., may involve calculations), then I can't > see what any of your ideas gain over the simple: > > class SomeObject > { > public: > SomeObject(int i, int percent) > { > setValue(i); > increaseRate(percent); > } > SomeObject& setValue(int i) > { > // do stuff with i > return *this; > } > SomeObject& increaseRate(int percent) > { > // do stuff with percent > return *this; > } > private: > // ... > }; > > void startCalculation(SomeObject) { } > > int main() > { > startCalculation(SomeObject(47, 20)); > } > > If they /are/ just initializations, then use a two-arg constructor and a > mem-initializer list. > > Though not intended to be merely a dig, I have picked up from other similar > ideas that you have presented that you have a leaning towards wanting to use > chaining at the call site to functions that starts to feel a little `unhealthy' > (i.e., counter-productive), especially when you are having to add layers of > inheritance, or whatever, just to make it `work'. No, it's not just to make it work. It's a safety extension. See below. > With respect, you might want > to ask yourself if you are doing it differently (i.e., against convention) > merely to /be/ different. > > I can't see how this: > > startCalculation( SomeObject().setValue( 47 ).increaseRate( 20 ) ); > > or, especially this: > > startCalculation( PreparedObject( 47, 20 ) ); > > can ever achieve anything - *especially* where you are passing a temporary that > doesn't exist outside of the call - over: > > startCalculation(SomeObject(47, 20)); > > Chaining is `pretty'. It doesn't always *solve* very much. > Please correct me if I'm wrong, but chaining is the only really good solution to provide optional parameters when the number of parameters grow large. Since the number of permutations of the optional parameters is so great I cannot have them in the constructor of SomeObject. My first thought was to create something like SomeObjectA SomeObjectB .... SomeObjectQ for each permutation, but I skipped that since I didn't want to force the programmer to create an object for each permutation, hence the general SomeObject with chaining. Now, I still want to provide the /ability/ of creating SomeObjectA, etc. (or functions) for the reason that it forces a compile-time check of the provided parameters. Now the programmer can pinpoint certain often-used permutations and make sure they will always get right. E.g. startCalculation( DefaultSettings() ); All ideas about optional parameters are welcome. Thanks for your input! -- [ See http://www.gotw.ca/resources/clcm.htm for info about ] [ comp.lang.c++.moderated. First time posters: Do this! ]
From: Jeff Flinn on 16 Jun 2010 02:46 DeMarcus wrote: > Paul Bibbings wrote: >> DeMarcus wrote: >>> Hi, .... > All ideas about optional parameters are welcome. Thanks for your input! Have you looked at http://www.boost.org/doc/libs/1_43_0/libs/parameter/doc/html/index.html Abstract: Use this library to write functions and class templates that can accept arguments by name: new_window("alert", _width=10, _titlebar=false); Since named arguments can be passed in any order, they are especially useful when a function or template has more than one parameter with a useful default value. The library also supports deduced parameters; that is to say, parameters whose identity can be deduced from their types. Jeff -- [ See http://www.gotw.ca/resources/clcm.htm for info about ] [ comp.lang.c++.moderated. First time posters: Do this! ]
From: Alf P. Steinbach on 16 Jun 2010 16:24 * DeMarcus, on 16.06.2010 15:57: > > Please correct me if I'm wrong, but chaining is the only really good > solution to provide optional parameters when the number of parameters > grow large. Jeff Flinn has alredy mentioned the Boost Parameters Library, which does not depend on chaining. But it is a bit impractical for constructor arguments in the context of inheritance. > Since the number of permutations of the optional parameters is so great > I cannot have them in the constructor of SomeObject. My first thought > was to create something like > > SomeObjectA > SomeObjectB > ... > SomeObjectQ > > for each permutation, but I skipped that since I didn't want to force > the programmer to create an object for each permutation, hence the > general SomeObject with chaining. > > Now, I still want to provide the /ability/ of creating SomeObjectA, etc. > (or functions) for the reason that it forces a compile-time check of the > provided parameters. Now the programmer can pinpoint certain often-used > permutations and make sure they will always get right. E.g. > > startCalculation( DefaultSettings() ); > > > All ideas about optional parameters are welcome. Thanks for your input! Usage examples for a general chaining-based solution that supports inheritance (i.e., it generates covariant setters) is available here: http://alfps.wordpress.com/2010/05/19/cppx-how-to-do-typed-optional-arguments-in-c98/ It links further to the FAQ, to a DDJ article, to an earlier article posted in this group, to earlier discussion in [comp.lang.c++], and to full code for the discussed general solution in a ZIP archive at Google Docs. The DDJ article additionally gives a usage example for the Boost Parameters Library (possibly not the cleanest possible but the best that I could think of), and discusses why BPAL may be undesirable and chaining preferable. Cheers & hth., - Alf -- blog at <url: http://alfps.wordpress.com> [ See http://www.gotw.ca/resources/clcm.htm for info about ] [ comp.lang.c++.moderated. First time posters: Do this! ]
First
|
Prev
|
Next
|
Last
Pages: 1 2 3 4 Prev: How to test if a iterator is valid or not? Next: return value optimization vs. returning a boost::shared_ptr of container |