// -*- C++ -*- // $RCSfile: elementfunction.h,v $ // $Revision: 1.5 $ // $Author: langer $ // $Date: 2000/12/05 21:30:32 $ /* This software was produced by NIST, an agency of the U.S. government, * and by statute is not subject to copyright in the United States. * Recipients of this software assume all responsibilities associated * with its operation, modification and maintenance. However, to * facilitate maintenance we ask that before distributing modifed * versions of this software, you first contact the authors at * oof_manager@ctcms.nist.gov. */ #ifndef ELEMENTFUNCTION_H #define ELEMENTFUNCTION_H // The ElementFunction classes define things that can be computed on // an Element. They are derived from this templated base class, which // takes care of things like putting the functions in the menus, and // making them accessible to the rest of the program. The derived // classes must look like this: // class StressXX : public ElementFunction { // public: // StressXX() {} // static CharString id() { return CharString("StressXX"); } // static double order() { return 1.0; } // virtual double operator()(Element &el) const { // return el.stresstensor()(0,0); // } // }; // template class ElementFunction; // Notes: // Although the ElementFunctions don't contain any non-static data, a // single instance of each function must be created, so that the // constructor can put each function in the menus, etc. In order to // do this in the base class, the type of the derived class is passed // to the base class (ElementFunction<>) as a template argument. That // means that the ElementFunction classes are all different types, so // the template ElementFunction<> is in turn derived from // ElementFunctionBase. ElementFunctionBase maintains the list of all // the ElementFunctions<>. // Because instances of these classes are created and used at startup // to construct the menus, they can't rely on static data for // initialization (there is no way to make sure that the // initialization data is created before the // ElementFunction). Therefore, instead of having a "static const // CharString name" data member, the classes have a function (id) // which returns the name. This function can't return a CharString&, // because to do that it would either have to return a reference to a // temporary, or the CharString would have to be a static member, and // we can't guarantee that *that* member would be constructed before // it's used. So, the derived class must return a plain old // CharString, which is inefficient. To relieve the inefficiency, // ElementFunction::name makes and stores a copy when needed, and returns a // reference to it. // The functions id() and order() must be static, because they are // used in the constructor of the ElementFunction<> base class. // The value returned by order() determines where this ElementFunction // will appear in menus. Lower orders come first. // Not all compilers catch the fact that these templates are actually // used, since they're not explicitly used anywhere: the only instance // of an object of the ElementFunction class is the static // instance declared within ElementFunction. The line // "template class ElementFunction" forces instantiation of // the template. // The SGI compiler can't seem to generate a default null constructor // and issues a warning if one isn't provided. Hence the line // "StressXX() {}" in the example above. #include "colordrawer.h" #include "elementfunctionbase.h" class CharString; template class ElementFunction : public ElementFunctionBase { public: virtual ~ElementFunction(); virtual const CharString &name() const; virtual double operator()(Element&) const = 0; static const EF &instance(); virtual double order_() const; // order in menus protected: ElementFunction(); private: static const EF instance_; // the single instance }; #include "elementfunction.C" #endif // ELEMENTFUNCTION_H