|
From: Carlos Moreno on 6 Jan 2008 22:55 I'm wondering if it is possible to do the following, perhaps with some pre-processor trickery? When providing a class, we usually provide a header file with the class declaration (and possibly some inline implementations), and an implementation file. My question is: is it possible for a given framework to require users of that framework (read: programmers that are using that framework to create their applications) to provide certain specific methods through an implementation file, and *not* as inline methods in their class declaration? I'll be a little more specific as to what I need to do: Following a discussion a while ago on the subject of "Automatic Serialization", one of the aspects that came up was the need to include in the programs some timestamp, so that if the program is recompiled (indicating that the layout of the data for the class may have changed), at run-time this can be known. So, my framework provides a base class representing the application, which is intended for users of the framework to derive from: ---- File application.h ---- class Application { public: Application () : d_compile_timestamp ( __DATE__ __TIME__ ) {} // ... }; ---- End File application.h ---- Users of the framework are supposed to create their file, say, my_custom_app.h, with the following: #include "application.h" class My_custom_app : public Application { // customize things }; The thing is, they will do this to create a customized "template" for a set of applications --- that is, they will then derive from My_custom_app to create multiple applicationss that are specific instances of the "template" that they created. But all of these specific instances of that template need to be in sync with respect to the timestamp --- that is, the executables corresponding to all of those need to be the same for the system to work. If they only provide a my_custom_app.h with the constructor defined inline, then things won't work --- every time that they compile each of the applications, those will get different compile timestamps. The only way it can work is if they provide a my_custom_app.c++ with the constructor defined in there --- and even then, that's provided that they compile and link in multiple steps, and that they don't unnecessarily recompile my_custom_app.c++ in between compilations of the various applications. So: is there a way for my framework to *require* that the constructor for classes immediately derived from class Application be defined through a .cpp file that is compiled to an object file and later linked with the various applications? Ideally, this would have to be a *pure C++* solution, and preferably platform-independent --- if platform independent is not possible, I would settle for a solution that works with g++ on Linux. Am I asking too much? Thanks, Carlos -- -- [ See http://www.gotw.ca/resources/clcm.htm for info about ] [ comp.lang.c++.moderated. First time posters: Do this! ]
From: Sean Hunt on 8 Jan 2008 22:30 On Jan 7, 8:55 am, Carlos Moreno <cm_n...(a)mailinator.com> wrote: > class Application > { > public: > Application () > : d_compile_timestamp ( __DATE__ __TIME__ ) > {} > > // ... > > }; This is actually illegal, since the definition of an inline function must be identical in every file. Sean -- [ See http://www.gotw.ca/resources/clcm.htm for info about ] [ comp.lang.c++.moderated. First time posters: Do this! ]
From: Maciej Sobczak on 8 Jan 2008 22:49 On 8 Sty, 23:40, Carlos Moreno <cm_n...(a)mailinator.com> wrote: > your ieda of a very simple, > possibly console-based or web-based application that simply creates > the skeleton sounds nice. Exactly - you don't need a full-blown IDE, nor any UML-based machinery. Even XML style sheets are surprisingly powerful and with a handful of Python/Perl/whatever scripts you can do miracles. > Notice, however, that it does not handle > the issue of the user manually compiling things --- if that file > my_custom_app.c++ is recompiled by the user between compilations > of custom_custom_app1 and custom_custom_app2, then these two are > now out of sync. You have mentioned something about Murphy and Machiavelli - what was that, exactly? ;-) Users don't compile things separately, they are too lazy. They just type make and press enter. Just make sure that makefiles are in sync with the rest, but this is easy to generate. Laziness of the framework users is a key point here - if some choice is already made for them (like the source file layout in this case), they don't bother elaborating it. This nicely protects against Murphy. -- Maciej Sobczak * www.msobczak.com * www.inspirel.com -- [ See http://www.gotw.ca/resources/clcm.htm for info about ] [ comp.lang.c++.moderated. First time posters: Do this! ]
From: Greg Herlihy on 9 Jan 2008 21:56 On Jan 7, 7:55 am, Carlos Moreno <cm_n...(a)mailinator.com> wrote: > > Following a discussion a while ago on the subject of "Automatic > Serialization", one of the aspects that came up was the need to > include in the programs some timestamp, so that if the program > is recompiled (indicating that the layout of the data for the class > may have changed), at run-time this can be known. > > So, my framework provides a base class representing the application, > which is intended for users of the framework to derive from: > > ---- File application.h ---- > > class Application > { > public: > Application () > : d_compile_timestamp ( __DATE__ __TIME__ ) > {} > > // ... > > }; The Application class declaration above appears to violate C++'s "one definition rule" (ODR) - specifically �3.2/5. The first bullet in that paragraph requires that the definition of a class must - in each translation unit in which the definition appears - consist of the same sequence of tokens. Yet the tokens that the preprocessor uses to replace __DATE__ and __TIME__ do not remain constant from one translation unit to the next. In fact,.because the date and time macros change so frequently, there is effecitvely no way to ensure that Application's d_compile_timestamp has a constant value initializer - let alone that d_compile_timestamp will have the same a value in both a derived and its base class. In short, using time stamps to track revisions to a class definition is simply not a workable solution. Instead of relying on a continually- changing time stamp value, the program really needs to find a value that changes only upon each revision of the class header file itself. Fortunately, there is at least one place where such a value can usually be found: the source code control system (SCCS) that manages the program's source code files. (And if, for some reason, the program's soruce files are not under SCCS control, then the first step is to check in those source files into an SCCS) Most of the popular SCCS systems widely used today, including cvs, subversion and perforce - can recognize something called "RCS keywords" - special tokens placed in source files as stand-in for values that the SCCS furnishes. So whenever the SCCS encounters one of these RCS keywords in a file, the SCCS replaces the keyword with the value that the keyword represents. (In this case, the RCS keyword of interest is $Revision$, that is, the revision number of the header file itself). For example, an Application class definition that uses RCS keyword to specify the value of the class version number, could look something like this: class Application { public: Application () : d_class_version ( $Revision$ ) {} // ... }; Now, whenever a client checks out the "application.h" header file, the SCCS will replace the $Revision$ keyword with the actual revision number of Application.h itself. Furthermore, since the class version number remains unchanged between class revisions, there is no need to ban inline constructors in user-code (a requirement that was as unenforceable as it was unreasonable in the first place.) Naturally, the specific details of this proposed solution are likely to vary somewhat - depending on the particular SCCS system in use. So, it likely will be necessary to consult the relevant SCCS documentation and to find which RCS keywords are recognized and what additional steps (if any) must be taken RCS keywords to be recognized. Greg -- [ See http://www.gotw.ca/resources/clcm.htm for info about ] [ comp.lang.c++.moderated. First time posters: Do this! ]
|
Pages: 1 Prev: std::ostream oddity Next: Exception class with shift operator |