   C++ questions
  Hi,I have been wondering about effective C++ usage.My first bunch of questions:Why has the C++ preprocessor not been improved from C?Do you think we can benefit from a new C++ preprocessor, for example FOG, or a new preprocessing model based on e.g. boost::wave? Could e.g. closures/lambda functions be implemented this way?Which non-obvious C++ ideoms do you know/find useful (e.g. template typedefs via rebind<> or boost::mpl's placeholders/apply, curiously recurring template pattern)? Please share your knowledge.What are your opinions regarding macro usage to simplify/document common C++ ideoms (like here)? Do you have some macro tricks to share?What is the difference between interface-based and object-oriented programmingShould there be an effort to create "universal" interfaces/template signatures for C++, which are stored in something like a CPAN for C++ and available for all developers to specialize? E.g. a universal ("general purpose") renderer<> template, which can be completely parametrized? Much of the work in C++ is boilerplate coding, so what can be done about it?Sorry if this is all fuzzy, I'm recovering from a good old katzenjammer. [sick]Food for thought:Comeau tech talk about templatesC++ faq liteC++ articles @ informit.com
Quote:What are your opinions regarding macro usage to simplify/document common C++ ideoms (like here)? Do you have some macro tricks to share?That article begins well - saying that the preprocessor has been abused in the past and that it does have some uses. However, the author quickly demonstrates that what he's proposing is full scale macro abuse.From the article - my personal favourite bit of $%*! being proposed:#define CLASS_CONSTANT(name,value) enum {name = value);What's wrong with 'const type name = value;' - surely that's clearer?Actually I lie - that one's my second favourite - this one's my favourite#define MEMBER_DATA protected:This is the problem with the internet - anyone can host any old rubbish.This one's pretty good too - it hides the from programmer the fact that the access mode has been set to public AND it returns by value instead of const reference.#define ACCESSOR(name, type, expr) public: type name() const {return expr;}Also the author apparently hasn't heard of typedef;according to him, a good use of macros would be...Quote:to facilitate transition to anticipated language improvements.{Those who declared every logical data item short or int regretted their non-use of a macro when bool was later introduced.);  I think one of my favorite preprocessor uses for documenting code I found recently was in the Windows DDK.#define IN#define OUT#define INOUTint func(IN int x, IN int y, OUT int& z);the values don't resolve to anything, but when you look at the function defintion, you can see which direction the variables are flowing.   ;  It gets even worse as templates are usually implemented entirely in header files and header files are done by the preprocessor.There is some ways to do preprocessor meta-programming I think but, the whole preprocessor and header files of C++ has turned me off to the language alot, I wonder why they improve the language so much and still use the same preprocessor technology from the '70's...   ;  I generally loath macros or constants using #defineI only use them in limited cases to simply save typing. I define them immediately before use and undefine immediately after use.For example:struct VK_String_Table{    std::vector<std::string> Table;    VK_String_Table();};VK_String_Table::VK_String_Table(){    #define AddString(S) Table.push_back(std::string(S))    AddString("--0");    AddString("Left Mouse");    AddString("Right Mouse");    AddString("BREAK");    AddString("Middle Mouse");    AddString("X1 Mouse");    AddString("X2 Mouse");    AddString("--7");    AddString("Backspace");    AddString("Tab");    AddString("--10");    AddString("--11");    AddString("Clear");    AddString("Enter");    AddString("--14");    AddString("--15");    AddString("Shift");AddString("Ctrl");AddString("Alt");    AddString("Pause");    AddString("Caps");    AddString("Hanguel");    AddString("--22");    AddString("Junja");    AddString("final");    AddString("Hanja");    AddString("--26");    AddString("Esc");    AddString("convert");    AddString("non-convert");    AddString("accept");    AddString("mode change request");    AddString("Space");    AddString("PageUp");    AddString("PageDown");    AddString("End");    AddString("Home");    AddString("Left");    AddString("Up");    AddString("Right");    AddString("Down");    AddString("Select");    AddString("Print");    AddString("Execute");    AddString("PrintScr");    AddString("Ins");    AddString("Del");    AddString("Help");    AddString("0");    AddString("1");    AddString("2");    AddString("3");    AddString("4");    AddString("5");    AddString("6");    AddString("7");    AddString("8");    AddString("9");    AddString("--58");   AddString("--59");    AddString("--60");    AddString("--61");    AddString("--62");    AddString("--63");    AddString("--64");    AddString("A");    AddString("B");    AddString("C");    AddString("D");    AddString("E");    AddString("F");    AddString("G");    AddString("H");    AddString("I");    AddString("J");    AddString("K");    AddString("L");    AddString("M");    AddString("N");    AddString("O");    AddString("P");    AddString("Q");    AddString("R");    AddString("S");    AddString("T");    AddString("U");    AddString("V");    AddString("W");    AddString("X");    AddString("Y");    AddString("Z");    AddString("L_WIN");    AddString("R_WIN");    AddString("APPS");    AddString("--94");    AddString("Sleep");    AddString("Num 0");    AddString("Num 1");    AddString("Num 2");    AddString("Num 3");    AddString("Num 4");    AddString("Num 5");    AddString("Num 6");    AddString("Num 7");    AddString("Num 8");    AddString("Num 9");    AddString("Num *");    AddString("Num +");    AddString("Separator");    AddString("Num -");    AddString("Num .");    AddString("Num /");    AddString("F1");    AddString("F2");    AddString("F3");    AddString("F4");    AddString("F5");    AddString("F6");    AddString("F7");    AddString("F8");    AddString("F9");    AddString("F10");    AddString("F11");    AddString("F12");    AddString("F13");    AddString("F14");    AddString("F15");    AddString("F16");    AddString("F17");    AddString("F18");    AddString("F19");    AddString("F20");    AddString("F21");    AddString("F22");    AddString("F23");    AddString("F24");    AddString("--136");    AddString("--137");    AddString("--138");    AddString("--139");    AddString("--140");    AddString("--141");    AddString("--142");    AddString("--143");    AddString("Num Lock");    AddString("Scroll Lock");    AddString("--146");    AddString("--147");    AddString("--148");    AddString("--149");    AddString("--150");    AddString("--151");    AddString("--152");    AddString("--153");    AddString("--154");    AddString("--155");    AddString("--156");    AddString("--157");    AddString("--158");    AddString("--159");    AddString("LShift");    AddString("Rshift");    AddString("LCrtl");    AddString("RCtrl");    AddString("LMenu");    AddString("RMenu");    AddString("Browser Back");    AddString("Browser Forward");    AddString("Browser Refresh");    AddString("Browser Stop");    AddString("Browser Search");    AddString("Browser Favorites");    AddString("Browser Home");    AddString("Volume Mute");    AddString("Volume Down");    AddString("Volume Up");    AddString("Next Track");    AddString("Previous Track");    AddString("Stop Media");    AddString("Play/Pause Media");    AddString("Start Mail");    AddString("Select Media");    AddString("Start Application 1");    AddString("Start Application 2");    AddString("--184");    AddString("--185");    AddString(";");    AddString("=");    AddString(",");    AddString("-");    AddString(".");    AddString("/");    AddString("~");    AddString("--193");    AddString("--194");    AddString("--195");    AddString("--196");    AddString("--197");    AddString("--198");    AddString("--199");    AddString("--200");    AddString("--201");    AddString("--202");    AddString("--203");    AddString("--204");    AddString("--205");    AddString("--206");    AddString("--207");    AddString("--208");    AddString("--209");    AddString("--210");    AddString("--211");    AddString("--212");    AddString("--213");    AddString("--214");    AddString("--215");    AddString("--216");    AddString("--217");    AddString("--218");    AddString("[");    AddString("\\");    AddString("]");    AddString("'");  AddString("--223");    AddString("--224");    AddString("--225");    AddString("--226");    AddString("--227");    AddString("PROCESSKEY");    AddString("--229");    AddString("PACKET");    AddString("--231");    AddString("Nokia RESET");    AddString("Nokia JUMP");    AddString("Nokia PA1");    AddString("Nokia PA2");    AddString("Nokia PA3");    AddString("Nokia WSCTRL");    AddString("Nokia CUSEL");    AddString("Nokia ATTN");    AddString("Nokia FINNISH");    AddString("Nokia COPY");    AddString("Nokia AUTO");    AddString("Nokia ENLW");    AddString("Nokia BACKTAB");    AddString("Attn");    AddString("CrSel");    AddString("ExSel");    AddString("Erase EOF");    AddString("Play");    AddString("Zoom");    AddString("NONAME");    AddString("PA1");    AddString("Clear ");    AddString("Multimedia");    #undef AddString}Although admittedly this should be reading strings from a file.   ;Quote:Original post by GrainI generally loath macros or constants using #defineI only use them in limited cases to simply save typing. I define them immediately before use and undefine immediately after use.For example:*** Source Snippet Removed ***Although admittedly this should be reading strings from a file.You might want to check out this.;  A lot of it is because of backwards compatiblity with C.  Some things in C++ were designed to help discourage the use by giving a better thing.  Like typedef to replace using macros.  Use of inline template functions to replace macros with a typesafe versions.   ;Quote:Original post by KonfusiusWhy has the C++ preprocessor not been improved from C?I'm assuming the most likely reason for backwards compatibility with C althougth C++ does not currently support additions made to macros in C99.Quote:Original post by KonfusiusDo you think we can benefit from a new C++ preprocessor, for example FOG, or a new preprocessing model based on e.g. boost::wave? Could e.g. closures/lambda functions be implemented this way?I don't know anything about FOG to make comments on but C++ would benefit from a more elaborate macro system & macro language like in Nemerle or common lisp than any form of preprocessor that simply does textual replacement this would make much preprocessor macro & template metaprogramming unnecessary/obsolete even more so when (if ever) C++ *natively* supports variadic templates.As far as i'm aware boost::wave is nothing more than a fully standard comforming implementation of C++ & C99 preprocessor.Also what did you mean by implementing closures/lambda functions, did you mean in C++? check out Phoenix 2.0 in particular check out the "Scope" section.Quote:Original post by KonfusiusWhich non-obvious C++ ideoms do you know/find useful (e.g. template typedefs via rebind<> or boost::mpl's placeholders/apply, curiously recurring template pattern)? Please share your knowledge.using boost.preprocessor & boost mpl together i guess is not commonly obvious among the masses.About advance techniques & idioms they can be all useful in the right place, so many to list best thing to do is get your hands on a thew decent books like Modern C++ Design: Generic Programming and Design Patterns Applied and C++ Template Metaprogramming : Concepts, Tools, and Techniques from Boost and Beyond they will give the concepts and correct terminology if i mention them you'll be like WTF is he talking about [wink].Quote:Original post by KonfusiusWhat are your opinions regarding macro usage to simplify/document common C++ ideoms (like here)? Do you have some macro tricks to share?In the wrong hands and used in an ad-hoc manner preprocessor macro can be evil, when used in a formalized way (like using boost.preprocessor) and in the right hands it can reduce alot of repetitive-boilerplate code which is a very good thing.Also template metaprogramming alone is not enough, it can reduce repetitive-boilerplate code of C++ code but due to *current* lacking features of templates, template metaprogramming actually can produce it's own set of repetitive-boilerplate meta-code *you need* boost.preprocessor to handle that if you want to migrate that problem.Here is an interesting "macro trick" (not mine): generates over 2200 functions for 1-dimensional arithmetic array manipulation in CQuote:Original post by KonfusiusWhat is the difference between interface-based and object-oriented programmingDepends on who you talk to, the term *interface-programming* can mean different things to different people, i'm assuming in the type sense of an "interface" in which case they are not mutually exclusive, "good OO" relies on it.Quote:Original post by KonfusiusShould there be an effort to create "universal" interfaces/template signatures for C++, which are stored in something like a CPAN for C++ and available for all developers to specialize? E.g. a universal ("general purpose") renderer<> template, which can be completely parametrized? Much of the work in C++ is boilerplate coding, so what can be done about it?I don't know how to respond to that [smile].[Edited by - snk_kid on December 7, 2005 2:12:03 PM];  Nitage, the enum thing is because enums are guaranteed compile-time-constant with no associated storage.  Not all compilers deal properly with static const's in classes. Quote:Original post by KonfusiusWhy has the C++ preprocessor not been improved from C?Because one of the goals of the language was to make the preprocessor (as) unnessesary (as practical).  Templates, constants, and inline functions are all intended to replace former usages of the preprocessor.It's better to weaken the preprocessor and strengthen the language because the preprocessor doesn't understand the language and therefore cannot deal with a great many things.For example, macros can't deal with template argument lists.  You couldn't use that ugly accessor macro above with a std::vector<int,boost::pool_allocator<int> >, for instance, because it would treat the comma as separating arguments to the macro.Quote:Original post by KonfusiusDo you think we can benefit from a new C++ preprocessor, for example FOG, or a new preprocessing model based on e.g. boost::wave? Could e.g. closures/lambda functions be implemented this way?I don't see how a preprocessor could do lambda fucntions any better than Boost.Lambda, unless it understood C++ syntax in which case it might as well just be part of the compiler.Quote:Original post by KonfusiusWhich non-obvious C++ ideoms do you know/find useful (e.g. template typedefs via rebind<> or boost::mpl's placeholders/apply, curiously recurring template pattern)? Please share your knowledge.Mixing static and dynamic polymorphism is possibly the best one, though it's not really an idiom.  Templates for strategies ("policies") can be quite useful too.Quote:Original post by KonfusiusWhat are your opinions regarding macro usage to simplify/document common C++ ideoms (like here)? Do you have some macro tricks to share?Most are a waste of time.  That IN and OUT one, for example, is totally unnessesary -- things passed by value or reference-to-const are in, things passed by pointers the function takes ownership of, and things returned or passed by reference-to-non-const are output.The only macro I've written recently is this one:#define ASSIST_FINALLY( func )    ??/::assist::guard ASSIST_FINALLY_ID( __LINE__ )    ??/  = ::assist::make_guard( func );  ??/ASSIST_FINALLY_ID( __LINE__ ).nop()#define ASSIST_FINALLY_ID(id) ASSIST_FINALLY_ID_IMPL(id)#define ASSIST_FINALLY_ID_IMPL(id) assist_finally_ ## idFor making unnamed, non-dismissable guards. ( see http://www.cuj.com/documents/s=8000/cujcexp1812alexandr/alexandr.htm for details about guards )The Boost.PreProcessor point is a good one though, for things like _Modern C++ Design_'s typelists and such.Quote:Original post by KonfusiusShould there be an effort to create "universal" interfaces/template signatures for C++, which are stored in something like a CPAN for C++ and available for all developers to specialize? E.g. a universal ("general purpose") renderer<> template, which can be completely parametrized? Much of the work in C++ is boilerplate coding, so what can be done about it?Boost.Lambda is pretty good at reducing boilerplate:std::sort( container.begin(), container.end(), bind( &renderable::z, _1 ) > bind( &renderable::z, _2 ) );If fact, that example is fine with just the 1.33 Boost.Bind.As for universal interfaces, universal tends to mean "so general as to be useless".   ;  My particular most useful macro hack is used when I want a long list with an enum indexing into an array or something similar, so I do this:parent.h:#define BEGIN_ARRAY array_element array[] =#define ARRAY_ELEMENT(a,b,c) {#a, b, c},#define END_ARRAY };#include "child.h"#undef BEGIN_ARRAY#undef ARRAY_ELEMENT#undef END_ARRAY#define BEGIN_ARRAY enum array_enum {#define ARRAY_ELEMENT(a,b,c) a,#define END_ARRAY };#include "child.h"#undef BEGIN_ARRAY#undef ARRAY_ELEMENT#undef END_ARRAYchild.h:BEGIN_ARRAYARRAY_ELEMENT(NAME1, 0, 1)ARRAY_ELEMENT(NAME2, 2, 3)ARRAY_ELEMENT(NAME3, 4, 5)END_ARRAY