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

Discussion in 'C++' started by Chris F Clark, Aug 24, 2004.

  1. 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 :
    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)
    ------------------------------------------------------------------------------
     
    Chris F Clark, Aug 24, 2004
    #1
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Ken Philips
    Replies:
    1
    Views:
    470
    Anthony Borla
    Feb 7, 2005
  2. Replies:
    5
    Views:
    286
    Jon Slaughter
    Oct 16, 2005
  3. Replies:
    10
    Views:
    675
  4. Replies:
    2
    Views:
    538
    James Kanze
    Mar 30, 2007
  5. brahatha
    Replies:
    1
    Views:
    684
Loading...

Share This Page