![](http://thenew.hp.com/img/s.gif) |
HP C++
HP C++ Class Library Reference Manual
Chapter 3 generic Package
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 a name for the class and specify the number of type
parameters:
#define YOUR_CLASS_NAME(TYPE_PARAMETER_NAME)
name2(TYPE_PARAMETER_NAME, YOUR_CLASS_NAME)
|
To specify two type parameters, use the
name3
macro.
- Define the class body as a macro:
#define YOUR_CLASS_NAMEdeclare(TYPE_PARAMETER_NAME) class {...};
#define YOUR_CLASS_NAMEimplement(TYPE_PARAMETER_NAME) ...
|
- Declare the actual class:
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.
- Define the functions or static data of the actual class.
implement(YOUR_CLASS_NAME, ACTUAL_TYPE_NAME)
|
You must do this once in each program that uses the parameterized
type with a given parameter.
- Declare an instance of the class you have declared by specifying
objects of type YOUR_CLASS_NAME(ACTUAL_TYPE_NAME), as follows:
YOUR_CLASS_NAME(ACTUAL_TYPE_NAME) object1, object2;
|
Global Declarations
These declarations are used by the generic package but they are not
members of any class.
Header
#include <generic.hxx>
Alternative Header
#include <generic.h>
Compile-Time Parameters
TYPE, TYPE1, TYPE2---The types for which
this class is parameterized; TYPE, TYPE1, or
TYPE2 must be an identifier.
CLASS---The class that is parameterized. For a vector of
integers, for example, CLASS is
vector
and TYPE is
int
.
Declarations
typedef int (*GPT)(int, char *);
int genericerror(int n, char *msg);
|
Type
GPT
Is a pointer to a generic error-handling function.
Function
int genericerror (int n, char *msg)
Is the default error-handling function; it prints an error number
(n) and message (msg) on
cerr
and calls
abort()
.
Macros
Macros provide preprocessor facilities for simulating parameterized
types. The following macros are defined for the generic package:
callerror(CLASS, TYPE, N, S)
Calls the current error handler for a given instance of a parameterized
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). 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(CLASS, TYPE)
Declares the class specified by a macro with the name of the generic
class. The word
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(CLASS, TYPE1,TYPE2)
Declares the class specified by a macro with the name of the generic
class. The name is followed by the word
declare2
. The
declare2
macro differs from the
declare
macro only in that you use it to declare two type parameters,
TYPE1 and TYPE2.
errorhandler(CLASS, TYPE)
Is the name of the pointer to the error handler for a given instance of
a parameterized class (for example,
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(CLASS, TYPE)
Defines the noninline member functions of a class, specified by a macro
with the name of the generic class. The name is followed by the word
implement
(for example,
vectorimplement
). The
implement
macro takes the same arguments as the
declare
macro.
implement2(CLASS, TYPE1,TYPE2)
Defines the noninline member functions of a class, specified by a macro
with the name of the generic class. The name is followed by the word
implement2
. The
implement2
macro differs from the
implement
macro only in that you use it to declare two type parameters,
TYPE1 and TYPE2.
name2(S1,S2)
Concatenates two identifier segments to form a new identifier using the
##
operator.
name3(S1,S2,S3)
Concatenates three identifier segments to form a new identifier using
the
##
operator.
name4(S1,S2,S3,S4)
Concatenates four identifier segments to form a new identifier using the
##
operator.
set_handler(CLASS, TYPE, HANDLER)
Specifies a function as the current error handler for a given instance
of a parameterized class. Initially, the error-handling function is set
to
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.
Example
The following program shows the use of the
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;
}
|
|