Can you make a template (w/ or w/o the pre-processor) solution to do this?

C

Chris F Clark

In our C++ project we have some internal bug reporting macros that we
use to get useful information when the program does something
unexpected. Essentially at the point of the error, we invoke an
internal interactive debugger that knows the [important] classes
within our system and allow us to walk around the objects that exist
at the time of the fault. It mostly works fairly well. That catch
being that we have to hand implement some of the code each of the
classes (thus the "important class" caveat), which suggests that what
we really need is a template based approach, since it would be much
nicer to have the system automatically generate an implementation for
all classes, eliminating the important/unimportant distinction.

In addition, our current implementation does not work in static member
functions, which is a secondary problem (but a key one if we go to a
template based approach). Currently, we can sidestep this problem
because we have no important classes that also have static member
functions that use the bug reporting macro. (Actually, this topic
came up because I just made a class "important" that had a static
member function that used the bug report macro, and I had to remove
the static member function from the class and make it a global
function to work around the limitation of our current scheme.)

Essentially, we want an ErrorHere function that works anywhere in our
code. If it is in a non-static member function of the class, it calls
the ErrorHereInClass virtual member function of the class which allows
the developer to see the data of the object being operated upon.
Anywhere else, we want the code to default to "assert(false)" like
behaviour. Our current implementation pretty much achieves that. In
objects that we care about, we have a few things that we add to the
class source code and then have an appropriate ErrorHereInClass
function that we can specialize. In classes where haven't done that,
we get the default implementation, which essentially prints out an
appropriate error.

Most of the functionality is implemented via an "ErrorHere" header
file. The ErrorHere header file defines a couple of classes and some
macros (to sugar things by hiding some of the internal mechanism).
The key macro appearing to be a set of functions that work like
"assert(false)", i.e. you call one of them when the code is in trouble
and it figures out how to best report to the user the location of the
problem.

Here is tersely what the ErrorHere header looks like:

class ErrorHereDeveloper; // controls some internal features

class ErrorHereClass {
public:
ErrorHereClass( ErrorHereDeveloper *dev ) :
errorHereDeveloper( dev )
{}
~ErrorHereClass();
virtual void ErrorHereInClass( const char *textToReport ) // overriden
{ cout << textToReport << endl; }
void ErrorHereReport( const char *textToReport )
{ ErrorHereInClass( textToReport ); }
protected: // data is here for this class and derived classes to use
ErrorHereDeveloper *errorHereDeveloper;
};

// default version that returns above "base" class
ErrorHereClass ErrorHereClassFactory( ErrorHereDeveloper *dev )
{
ErrorHereClass mine( dev );
return mine;
}

// use this call when any developer can handle this bug
extern void ErrorHere( const char *textToReport, ... );
extern class ErrorHereDeveloper *anyone;
#define ErrorHere ErrorHereClassFactory( anyone ).ErrorHereReport

// I use this call when I want users to report the bug only to me
extern void ErrorHereForChris( const char *textToReport, ... );
extern class ErrorHereDeveloper *chris;
#define ErrorHere ErrorHereClassFactory( chris ).ErrorHereReport

.. . .

As you can see, a "call" to ErrorHere in the pressence of just this
header file,calls the "global" ErrorHereClassFactory which retunrs a
class where the ErrorHereReport function takes and simply prints the
string (using a virtual function). Of course, our real implementation
does something more complex, but this is the essential "base"
functionality.

Now, let's look at a customized class, say "Square":

class ErrorHereClassSquare;

class Square {
ErrorHereClassSquare ErrorHereClassFactory( ErrorHereDeveloper *dev )
{
ErrorHereClassSquare mine( this, dev );
return mine;
}
virtual void ErrorHereInClass( const char *textToReport )
{ cout << "Square[" << length << ", " << width << "]: " <<
textToReport << endl; }
// rest of Square
. . .
int length, width; // (ok, maybe I meant rectangle!)
};

class ErrorHereClassSquare : public ErrorHereClass {
public:
ErrorHereClassSquare( Square *square; ErrorHereDeveloper *dev )
: ErrorHereClass( dev ),
mySquare( square )
{}
~ErrorHereClassSquare();
virtual void ErrorHereInClass( const char *textToReport ) // override
{ if ( square ) square->ErrorHereInClass( textToReport );
else cout << textToReport << endl; }
private:
Square *mySquare;
};

So, as you can see, the special class ErrorHereClassSquare and the per
class function ErrorHereClassFactory allows us to customize the code
for our classes. However, this code is "boilerplate" and it would be
nice if we could somehow use a template to create them. I think I
understand how to write the template that will create the
ErrorHere<ClassSquare>. That seems relatively straight forward.

However, it would also be nice, if we could somehow get the
functionality to work in static member functions, i.e. to have
something that would "revert" to the default implementation if the
"this" pointer wasn't available. I have no idea how to make a
(function?) template that tests its current context and determines if
the function it is being called within has a "this" pointer or not.
My fear is that since we make ErrorHere calls through-out our code
(including in static member functions and non-member functions) that
if we attempt ErrorHere in a static member function with a template
solution in place, that this will result in a call to the template
class constructor for the corresponding ErrorHere<Class> without
having a this pointer to pass to the class. At least that's what
happens when I define a per class ErrorClassFactory method in a class
that makes ErrorHere calls from static member functions.

I apologize if this is trivial to accomplish, but it is just too
subtle for me and my meager template programming ability. In the end
I would like something that works within the limits of both Visual C++
6.x and g++ 3.2.3.

-Chris

*****************************************************************************
Chris Clark Internet : (e-mail address removed)
Compiler Resources, Inc. Web Site : http://world.std.com/~compres
23 Bailey Rd voice : (508) 435-5016
Berlin, MA 01503 USA fax : (978) 838-0263 (24 hours)
------------------------------------------------------------------------------
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,768
Messages
2,569,574
Members
45,048
Latest member
verona

Latest Threads

Top