This is an attempt to sort out the coding guidelines I am consciously or unconsciously using. It should help sorting out the reworked dE libraries.
The language is ANSI C, compiled as C++, and C++ according to the proposed ANSI C++ standards. C++ features are used as implemented in GCC 2.7.2 or above, which unfortunately, means far from being complete. There is not stable stupport for namespaces, exceptions, RTTI. It seems that optimization is broken in some regards.
File names are not DOS-restricted. The following conventions are used:
This means that a header only contains declarations. The inline definitions should be separated inside the header file. Convenient exception: single line inlines like { return _somthing; } in classes.
Any template definition (potential inline) has to be put in *.t.C.
There are alternatives using *.C files:
As there won't be a working template instantiation repository mechanism for quite some time, we will rely on explicit template instantiation.
Thus we will have to handle the following fragment of code very often:
#pragma implementation #include"this.H" #include"this.t.C" template <class T> tAnyBase_OfThisTemplate<tAnyType>; template <class T> tThisTemplate_Itself<tAnyType>;
Note that explicit instantiation means that any base (class) template has to be instantiated, too. This has to be done manually. Template instantiations will put into the same *.C files in which the implementation of the template parameter class is done.
The following files have to be present in every directory, and are maintained by CVS:
configure.in - input for autoconf to generate configure Makefile.in - input for configure to generate Makefile aclocal.m4 - for configureThe following files have to be available in ./bin:
install.sh - for install
The following directories have to be present within the dE directory tree:
To avoid multiple inclusion by CPP, the following lines are used with SomeFile.H:
#ifndef __DE_SOME_FILE_H #define __DE_SOME_FILE_H #include <whatever.h> #include "WhatEver.H" #ifdef __GNUG__ #pragma interface #endif ... #endif
Note the use of Pragma, which corresponds to the following standard lines in the implementation *.C file only:
#include <whatever.h> #include "WhatEver.H" #ifdef __GNUG__ #pragma implementation "SomeFile.H" #endif #include "SomeFile.H"
Handling pointer return values: e.g. for the tString and tName
classes, it will be necessary to convert const char*
for I/O and other purposes. There are the following possible
operators:
operator char*(); // Not done. operator char*() const; // Definitely not done. operator const char*(); // Note done. See below. operator const char*() const; // Done.In principle, pointer return values provide means to access the internal state of an object. This is not a good idea. We have to make sure that the object's content cannot be changed (thus
const char*
), and we indicate that the
operation can be applied to const cObjects as well (thus
operator () const
). In principle, there is the
possibility to use const char const *
. I have to
think each time, thus here it is:
char* something; // Nothing is const. const char* something; // content is const. char* const something; // pointer is const. const char* const something; // Everything is const.Obviously, as the pointer itself is just a variable, it makes no sense to require it being const. Thus protecting the content pointed to is sufficient.
The same considerations made for pointer return values apply to reference return values. In case of simpe scalar returns, it is a good idea to implement both
char& operator[] ( int index ); char& operator[] ( int index ) const;for read/write access to non-const objects, and read-only access to const objects. In general, reference return values should be prefered, as it is not necessary to check for NULL (getting a type-secure NULL is a problem in itself). This will not work in all cases you want to return NULL if a requested object is not available.