|
From: Vidar Hasfjord on 14 Apr 2008 03:43 In C++ you cannot declare new user-defined operators, i.e. it is impossible to define a new operator token with a specified precedent and meaning, e.g. the euro symbol (EURO) to convert a value into euro cents. It is possible to simulate this to some degree using an object of a user-defined class with an operator overload. For example, with an "operator" object named E with a operator % overload, we can write (E% v) to mean some operation on v. I've found great utility for this idiom in two areas: error code checking and resource string loading (internationalisation). For example, with E% as a error-check operator and SL% as a string load operator I can write: E%DeleteFile (file); // throws on error and string caption = SL%IDS_VALIDATION_ERROR; // i18n string message = format (SL%IDS_OUT_OF_RANGE) % value; MessageBox (message, caption); While I think such operator use may be considered obfuscation in the general case, I think it has merits when it forms an idiom used in large parts of the code. But would this code pass your code review? Opinions welcome. Regards, Vidar Hasfjord -- [ See http://www.gotw.ca/resources/clcm.htm for info about ] [ comp.lang.c++.moderated. First time posters: Do this! ]
From: Michael Aaron Safyan on 14 Apr 2008 12:25 Using operator% in this manner would never pass my code review, because this usage has absolutely nothing to do with taking the modulus of a value, and -- therefore -- this usage is unintuitive. For the first example, why write "to_euros % some_value" when you can just as easily write "to_euros(some_value)"? For the second example, functions should throw exceptions, by default. If you don't want a function to throw exceptions, then they should be explicitly disabled as in the following: disable_exceptions{ // code which normally throws exceptions ceases to throw exceptions } The above can be implemented with something along the lines of: class ExceptionDisabler { public: ExceptionDisabler() : _test(true) { ExceptionManager::push(false); // disable } ~ExceptionDisabler(){ ExceptionManager::pop(); // restore } void operator++(){ _test = false; } void operator++(int){ _test = false; } operator bool()const{ return _test; } private: bool _test; }; #define TOKENCAT(X,Y) TOKENCAT2(X,Y) #define TOKENCAT2(X,Y) X ## Y #define disable_exceptions \ for ( ExceptionDisabler TOKENCAT(ed,__LINE__); \ TOKENCAT(ed,__LINE__); \ TOKENCAT(ed,__LINE__)++ ) \ -- [ See http://www.gotw.ca/resources/clcm.htm for info about ] [ comp.lang.c++.moderated. First time posters: Do this! ]
From: Martin T. on 15 Apr 2008 03:28 Vidar Hasfjord wrote: > In C++ you cannot declare new user-defined operators, i.e. it is > impossible to define a new operator token with a specified precedent > and meaning, e.g. the euro symbol (EURO) to convert a value into euro > cents. > > It is possible to simulate this to some degree using an object of a > user-defined class with an operator overload. For example, with an > "operator" object named E with a operator % overload, we can write (E% > v) to mean some operation on v. > > I've found great utility for this idiom in two areas: error code > checking and resource string loading (internationalisation). For > example, with E% as a error-check operator and SL% as a string load > operator I can write: > > E%DeleteFile (file); // throws on error > > and > > string caption = SL%IDS_VALIDATION_ERROR; // i18n > string message = format (SL%IDS_OUT_OF_RANGE) % value; > MessageBox (message, caption); > > While I think such operator use may be considered obfuscation in the > general case, I think it has merits when it forms an idiom used in > large parts of the code. But would this code pass your code review? > Opinions welcome. > What are the merits of this solution over just using a set for ctors for the E and SL classes? E(DeleteFile(file)); string message = format (SL(IDS_OUT_OF_RANGE)) % value; br, Martin -- [ See http://www.gotw.ca/resources/clcm.htm for info about ] [ comp.lang.c++.moderated. First time posters: Do this! ]
From: Edward Rosten on 15 Apr 2008 03:33 On Apr 14, 9:25 pm, Michael Aaron Safyan <michaelsaf...(a)aim.com> wrote: > Using operator% in this manner would never pass my code review, because > this usage has absolutely nothing to do with taking the modulus of a > value, and -- therefore -- this usage is unintuitive. Out of interest, would any of the following code pass your review: cout << "Hello, world." << endl; or string s; .... s += "Hello, world."; These expressions have respectively nothing to do with bit-shifting or addition. -Ed -- (You can't go wrong with psycho-rats.)(http://mi.eng.cam.ac.uk/~er258) /d{def}def/f{/Times s selectfont}d/s{11}d/r{roll}d f 2/m{moveto}d -1 r 230 350 m 0 1 179{ 1 index show 88 rotate 4 mul 0 rmoveto}for/s 12 d f pop 235 420 translate 0 0 moveto 1 2 scale show showpage [ See http://www.gotw.ca/resources/clcm.htm for info about ] [ comp.lang.c++.moderated. First time posters: Do this! ]
From: Alberto Ganesh Barbati on 15 Apr 2008 14:19
Michael Aaron Safyan ha scritto: > > For the second example, functions should throw exceptions, by default. > If you don't want a function to throw exceptions, then they should be > explicitly disabled as in the following: > > disable_exceptions{ > // code which normally throws exceptions ceases to throw exceptions > } > I really don't see the relationship with the OP's example. Moreover, it seems to me that it's a bad idea in the first place: if a function is designed to throw an exception to return an error condition and you disallow that, what should the function do to return the error condition? If the function calls a library function which is not under your control, how can you disallow exception thrown by the library function? In the end, it's much safer to wrap the code in a try/catch block rather than using your approach. > The above can be implemented with something along the lines of: > > class ExceptionDisabler > { > public: > ExceptionDisabler() : _test(true) { > ExceptionManager::push(false); // disable > } > ~ExceptionDisabler(){ > ExceptionManager::pop(); // restore > } > > void operator++(){ _test = false; } > void operator++(int){ _test = false; } > operator bool()const{ return _test; } > private: > bool _test; > }; > > #define TOKENCAT(X,Y) TOKENCAT2(X,Y) > #define TOKENCAT2(X,Y) X ## Y > > #define disable_exceptions \ > for ( ExceptionDisabler TOKENCAT(ed,__LINE__); \ > TOKENCAT(ed,__LINE__); \ > TOKENCAT(ed,__LINE__)++ ) \ > BTW, there is simpler a way of implementing this that doesn't require a loop: class ExceptionDisabler { public: ExceptionDisabler(int) { ExceptionManager::push(false); // disable } ~ExceptionDisabler() { ExceptionManager::pop(); // restore } operator bool() const { return false; } }; #define TOKENCAT(X,Y) TOKENCAT2(X,Y) #define TOKENCAT2(X,Y) X ## Y #define disable_exceptions \ if (ExceptionDisabler TOKENCAT(ed,__LINE__) = 0) {} else HTH, Ganesh -- [ See http://www.gotw.ca/resources/clcm.htm for info about ] [ comp.lang.c++.moderated. First time posters: Do this! ] |