|
|
|
|
||||||
![]() |
|
|
LinkBack | Outils de la discussion |
|
|
#1 |
|
Messages: n/a
Hébergeur: |
In a public include file, how can I declare an object and instantiate an
object all in one line, avoid seemingly duplicate information? I am typically used to doing something like the following, but I've never liked having to provide two lines related to the same object: extern MyClass obj1; extern MyClass obj2; #if defined( INSTANTIATE_OBJECTS ) MyClass obj1( 111 ); MyClass obj2( 222 ); #endif In one and only one C++ file, I would define INSTATIATE_OBJECTS to force the instantiate. I'm hoping to find a C-preprocessor trick that would let me use a single line to both declare and instantiate an object, depending on the value of a preprocessor macro. For example, I could use something like this (if I could embed a "//" comment into a macro definition): #if defined( INSTANTIATE_OBJECTS) #define DECLARE_VS_DEFINE #else #define DECLARE_VS_DEFINE ; // #endif extern MyClass obj1 DECLARE_VS_DEFINE ( 111 ); extern MyClass obj2 DECLARE_VS_DEFINE ( 222 ); Does such a preprocessor macro trick exist? Is there another way to do it? It would have to work with the Visual C compiler and GNU GCC. Thanks, Ed Jubenville |
|
|
|
#2 |
|
Messages: n/a
Hébergeur: |
Ed J wrote:
> In a public include file, how can I declare an object and instantiate > an object all in one line, avoid seemingly duplicate information?[..] Never instantiate an object in a header. As soon as the header is included in more than one translation unit (and if it isn't why it is a header, right?), you get the object defined more than once. V -- Please remove capital 'A's when replying by e-mail I do not respond to top-posted replies, please don't ask |
|
|
|
#3 |
|
Messages: n/a
Hébergeur: |
Ed J wrote:
> In a public include file, how can I declare an object and instantiate > an object all in one line, avoid seemingly duplicate information? I > am typically used to doing something like the following, but I've > never liked having to provide two lines related to the same object: > > extern MyClass obj1; > extern MyClass obj2; > #if defined( INSTANTIATE_OBJECTS ) > MyClass obj1( 111 ); > MyClass obj2( 222 ); > #endif > > In one and only one C++ file, I would define INSTATIATE_OBJECTS to > force the instantiate. > > I'm hoping to find a C-preprocessor trick that would let me use a > single line to both declare and instantiate an object, depending on > the value of a preprocessor macro. For example, I could use > something like this (if I could embed a "//" comment into a macro > definition): > #if defined( INSTANTIATE_OBJECTS) > #define DECLARE_VS_DEFINE > #else > #define DECLARE_VS_DEFINE ; // > #endif > extern MyClass obj1 DECLARE_VS_DEFINE ( 111 ); > extern MyClass obj2 DECLARE_VS_DEFINE ( 222 ); > > Does such a preprocessor macro trick exist? Is there another way to > do it? It would have to work with the Visual C compiler and GNU GCC. As V says, you don't. That's why we have header files and source files. Why can't you just put MyClass obj1( 111 ); MyClass obj2( 222 ); in a .c file and include it in your project? That's the way the language is designed. -- Jim Langston tazmaster@rocketmail.com |
|
|
|
#4 |
|
Messages: n/a
Hébergeur: |
Victor Bazarov wrote:
> Never instantiate an object in a header. As soon as the header is > included in more than one translation unit (and if it isn't why it > is a header, right?), you get the object defined more than once. The object doesn't get defined more than once if the programmer (me) follows the rules: 1. In ordinary source (.c) files wishing access to the declarations, I simply do: #include "filename.h" 2. In one and only one source file, I define INSTANSTIATE_OBJECTS before including the file, and it gives me the declaration and the instantiation: #define INSTANTIATE_OBJECTS #include "filename.h" I've used this technique many times on simple uninitialized variables to avoid the hassle of maintaining two different source files (the .h and .c) with the same object names. A typical xyz.h file would contain something like this: #if defined( INSTANTIATE_XYZ_OBJECTS ) #define EXTERN #else #define EXTERN extern #endif EXTERN int xyz1; EXTERN int xyz2; That single block of source code serves both the purpose of declaration and instantiation of xyz1 and xyz2, depending on whether the including .c file first declares INSTANTIATE_XYZ_OBJECTS. But this technique only works for uninitialized variables. I'm trying to find a similar technique for initialized variables. Editorial... It is a pet peeve of mine that the C and C++ languages require me to create two source code lines (one in a .c file, and one in a .h file) associated with the same object name. Simply put, one source code line is easier to maintain than two source code lines, especially when those two source code lines must, by edict of C/C++, reside in separate files. That's edict is a maintenance hassle that I would gladly circumvent if I knew how. Any ideas? |
|
|
|
#5 |
|
Messages: n/a
Hébergeur: |
On Feb 27, 2:15 pm, "Ed J" <j...@privacy.net> wrote:
[snip] Something along the lines of: #ifdef INSTANTIATE_XYZ_OBJECTS # define XYZ_EXTERN # define XYZ_ARGS(args) args #else # define XYZ_EXTERN extern # define XYZ_ARGS(args) #endif // no args XYZ_EXTERN MyClass (obj0a); XYZ_EXTERN MyClass (obj0b) XYZ_ARGS (()); // 1 arg XYZ_EXTERN MyClass (obj1) XYZ_ARGS ((111)); // 2 args XYZ_EXTERN MyClass (obj2) XYZ_ARGS ((111, 222)); But as others have pointed out it's a BAD IDEA. There are plenty of ways you can abuse the preprocessor, why stop there? You could just as well move all your source code into "headers" and conditionally compile-out function bodies depending on some macro. Or "#define BEGIN {" so it looks more like Pascal. Think of the sanity of the next guy who will be maintaining this code. In your example trying to grep the source files for these globals' definitions won't work anymore; the meaning of these weird macros is not obvious, etc. D. |
|
|
|
#6 |
|
Messages: n/a
Hébergeur: |
On Feb 27, 2:15 pm, "Ed J" <j...@privacy.net> wrote:
> The object doesn't get defined more than once if the programmer (me) follows > the rules: > 1. In ordinary source (.c) files wishing access to the declarations, I > simply do: > #include "filename.h" > 2. In one and only one source file, I define INSTANSTIATE_OBJECTS before > including the file, and it gives me the declaration and the instantiation: > #define INSTANTIATE_OBJECTS > #include "filename.h" This is -exactly- equivalent to just putting the object declarations in the header and putting the definition in one of the source files (the source file you #define INSTANTIATE_OBJECTS in). Except doing it with precompiler macros is slightly more work than you need to be doing, and also requires you to explain what you are doing to other people reading your code (whereas declaring objects as extern, possibly with a comment like "// defined in file.cpp", is clear and concise). > I've used this technique many times on simple uninitialized variables to > avoid the hassle of maintaining two different source files (the .h and .c) > with the same object names. A typical xyz.h file would contain something > like this: It depends on how you look at it I guess. If you are going by "number of files" then I guess having a .h file is "better" than having both a source and a header. If you are going by "lines of code", you are probably typing more with your preprocessor stuff. Also in either case, you still have the dependency on a given source file. With your method, if you remove the source file that #defines INSTANTIATE_OBJECTS, you have to put that #define somewhere else. With the other method, you still have to compile the source file with the definitions into the project -- but at least it's clear that "globals.cpp" matches "globals.h", rather than you saying "well if something_unrelated.cpp isn't compiled then the objects declared in globals.h won't be defined unless you move such and such preprocessor definition to another arbitrary source file". Both C and C++ have constructs and mechanisms ("extern", and the linker) to cleanly and clearly do -precisely- what you are doing with precompiler macros. > #if defined( INSTANTIATE_XYZ_OBJECTS ) > #define EXTERN > #else > #define EXTERN extern > #endif > EXTERN int xyz1; > EXTERN int xyz2; > > That single block of source code serves both the purpose of declaration and > instantiation of xyz1 and xyz2, depending on whether the including .c file > first declares INSTANTIATE_XYZ_OBJECTS. Until somebody sees that you only named it "EXTERN", and starts using EXTERN as a substitution for the real extern, expecting it to behave sanely. If you insist on doing it this way instead of just defining the objects in another source file, at least pick a better macro name than EXTERN. > But this technique only works for > uninitialized variables. I'm trying to find a similar technique for > initialized variables. You do it like this: header.h: extern int xyz1; extern int xyz2; one_source_file.cpp: int xyz1 = 400; int xyz2 = 234; Again, if you insist on doing it with precompiler macros, you would do this: extern int xyz1; extern int xyz2; #ifdef INSTANTIATE_XYZ_OBJECTS int xyz1 = 400; int xyz2 = 234; #endif Having the declaration and definition in the same source file won't cause any problems, there is no need to put the "extern int" declarations in an #else block. But again, since you are only #defining INSTANTIATE_XYZ_OBJECTS in a single source file before #including that header, you don't have to bother with the preprocessor at all -- just put the definitions right in that source file. > Editorial... It is a pet peeve of mine that the C and C++ languages require > me to create two source code lines (one in a .c file, and one in a .h file) > associated with the same object name. Simply put, one source code line is > easier to maintain than two source code lines, especially when those two > source code lines must, by edict of C/C++, reside in separate files. That's > edict is a maintenance hassle that I would gladly circumvent if I knew how. The reason for this is that you need to have the declaration of an object available so that the compiler knows it exists, and thus knows the type of it and can compile your code. However, the object itself is only defined in one translation unit. Declaration and definition are two separate concepts. There is no other alternative. Let's say that "declarations" didn't exist and you had to define everything everywhere. What happens if you put: int i = 3; In a header, and that serves as both declaration and definition? Then you compile multiple source files that use it. Then you change it to: int i = 4; And recompile only some of the source files. Or if it is a variable, such as errno, that is defined in a library elsewhere (where you have no control over the initialization of it -- yet you would still be "initializing" it to a certain value in errno.h). A situation like that would become a maintenance nightmare. You are already running into a situation where you have to maintain a separate declaration and definition for variables (you have to do this with functions, too -- you have to have *some* way of saying "this function exists" without repeating the code for it in every header you use it in). As you can see, it actually *is* useful to have separate declarations and definitions -- this completely solves your problem of wanting to use initialized data in multiple source files. You may want to consider removing that pet peeve from your list of pet peeves! > Any ideas? So what it comes down to is: use the language features that are already in place for doing exactly what you are trying to do. Declare variables, as extern, in headers, define them in a single source file, and don't use the preprocessor to emulate a feature that the language already has. Jason |
|
![]() |
| Outils de la discussion | |
|
|