The generic package provides ways to simulate parameterized types by allowing the instantiation of class declarations using the macro facilities of the C++ preprocessor. You can use the generic package to construct container classes. The actual types of the data members are passed at compile time as parameters to the class when you use the class name.
To declare a generic type:
#define YOUR_CLASS_NAME(TYPE_PARAMETER_NAME) name2(TYPE_PARAMETER_NAME, YOUR_CLASS_NAME)
To specify two type parameters, use the name3 macro.
#define YOUR_CLASS_NAMEdeclare(TYPE_PARAMETER_NAME) class { . . . };
#define YOUR_CLASS_NAMEimplement(TYPE_PARAMETER_NAME) . . .
declare(YOUR_CLASS_NAME, ACTUAL_TYPE_NAME)
By substituting one or another class of ACTUAL_TYPE_
NAME, you can declare multiple instances of the generic
class template with various component types. For example,
depending on the type parameter you use, you can declare such
types as list of int s, list
of String s, or list of lists
of String s.
If it is not a type name, ACTUAL_TYPE_NAME must be a
typedef name.
You must do this in each compilation unit that uses the parameterized type with a given parameter.
implement(YOUR_CLASS_NAME, ACTUAL_TYPE_NAME)
You must do this once in each program that uses the parameterized type with a given parameter.
YOUR_CLASS_NAME(ACTUAL_TYPE_NAME) object1, object2;
These declarations are used by the generic package but they are not members of any class.
#include <generic.hxx>
#include <generic.h>
vector and
TYPE is int .
typedef int (*GPT)(int, char *); int genericerror(int n, char *msg);
cerr
and calls abort() . vector ). TYPE denotes
the type parameter for which to instantiate the generic class
(for example, int to get a vector of integers); the
type must be an identifier (for example, char* is
not valid). N denotes the first argument to pass to the
error handler; the default is the function genericerror(int,
char*) . S denotes the second argument to pass to
the error handler. declare follows the class
name (for example, vectordeclare ). It also defines
the inline member functions of the class. CLASS denotes
the name of the generic class (for example, vector ).
TYPE denotes the type parameter for which to instantiate
the generic class (for example, int to get a vector
of integers). The type must be an identifier (for example,
char* is not valid). declare2 . The declare2 macro differs
from the declare macro only in that you use it to
declare two type parameters, TYPE1 and TYPE2.
intvectorhandler to handle errors for a vector of
integers). CLASS denotes the name of the generic class
(for example, vector ). TYPE denotes the type
parameter for which to instantiate the generic class (for example,
int to get a vector of integers). The type must be
an identifier (for example, char* is not valid).
implement (for example,
vectorimplement ). The implement macro
takes the same arguments as the declare macro.
implement2 . The implement2
macro differs from the implement macro only in that
you use it to declare two type parameters, TYPE1 and
TYPE2. ## operator. ## operator. ## operator. genericerror(int, char*)
. CLASS denotes the name of the generic class (for
example, vector ). TYPE denotes the type
parameter for which to instantiate the generic class (for example,
int to get a vector of integers); the type must be
an identifier (for example, char* is not valid).
HANDLER denotes a pointer to the function you want to
set to the new error handler. Also, you can use the set_
handler macro in a function declaration or definition. genericerror
function and associated macros:
extern "C"
{
#include <stdlib.h>
#include <stddef.h>
#include <stdio.h>
}
#include <generic.hxx>
#define my_vector(T) name2(T, my_vector)
// Declare a vector of objects of type T (the class and extern data)
#define my_vectordeclare(T) \
class my_vector(T) \
{ \
private: \
int s; \
T *p; \
public: \
my_vector(T)(int); \
~my_vector(T)(); \
T &operator[](int); \
}; \
extern GPT errorhandler(my_vector, T); \
extern GPT set_handler(my_vector, T, GPT);
// Implement a vector of objects of type T
// (Define the functions and global data)
#define my_vectorimplement(T) \
my_vector(T)::my_vector(T)(int size) \
{ \
s = size; \
p = new T[size]; \
} \
my_vector(T)::~my_vector(T)() \
{ \
delete[] p; \
} \
T &my_vector(T)::operator[](int i) \
{ \
if(i < 0 || i >= s) \
{ \
callerror(my_vector, T, i, "Index out of bounds"); \
static T error_object; \
return error_object; \
} \
return p[i]; \
} \
GPT errorhandler(my_vector, T) = &genericerror; \
GPT set_handler(my_vector, T, GPT new_genericerror) \
{ \
GPT old_genericerror = errorhandler(my_vector, T); \
errorhandler(my_vector, T) = new_genericerror; \
return old_genericerror; \
}
// Declare and implement vector of int
declare(my_vector, int)
implement(my_vector, int)
// Error-handling function
my_handler(
int n,
char *msg
)
{
fflush(stderr);
printf("in my_handler(%d,\"%s\")\n", n, msg);
fflush(stdout);
return 0;
}
int main(int argc, char *argv[])
{
my_vector(int) v1(10);
GPT old_error_handler;
// Set the handler to a function that does not abort
old_error_handler = set_handler(my_vector, int, &my_handler);
v1[12345] = 0;
// Restore the handler and cause an error
// This should abort
old_error_handler = set_handler(my_vector, int, old_error_handler);
v1[12345] = 0;
return EXIT_SUCCESS;
}