Listing 1: NamedVal.h — Defines classes SimpleDB, IOAble, IOParamBlock, and template class NamedVal

#ifndef __NAMEDVAL_H__
#define __NAMEDVAL_H__

#include <string>
#include <iostream>
#include <strstream>
#include <vector>

// Minimal INI file or registry interface. Console I/O for 
// testing will be overridden by real I/O functions 
class SimpleDB {
public:
   virtual void Write(const char *section, const char *key, 
                      const char *valStr) {
     std::cout << "[" << section << "]   " << key << "=" 
               << valStr << std::endl; 
   } 
   virtual void Read(const char *section, const char *key, 
                     char *valStr, int maxBufLen) {
     std::cout << "enter value for [" << section << "] key=" 
               << key << std::endl;
     std::cin >> valStr;
   }
};

class IOAble {
public:
   virtual void Write(SimpleDB &db, const char *section)=0;
   virtual void Read(SimpleDB &db, const char *section)=0;
};

class IOParamBlock
{
public:
   std::vector<IOAble *> ioVars;
   void AddVar(IOAble *v) { ioVars.push_back(v); }
   void WriteAll(SimpleDB &db, const char *section) { 
      int i; 
      for (i=0; i<ioVars.size(); i++) 
         ioVars[i]->Write(db, section);
   }
   void ReadAll(SimpleDB &db, const char *section) { 
      int i; 
      for (i=0; i<ioVars.size(); i++) 
         ioVars[i]->Read(db, section);
   }
};


// Template class that wraps a value of type T and has a string 
// as its name. Can also be inserted into IOParamBlock for 
// automatic IO
template <class T> class NamedVal : public IOAble {
protected:
   std::string name;
   T val;
public:
   NamedVal(const char *varName, const T& initialVal=T()) 
      : name(varName), val(initialVal) {}
   NamedVal(const NamedVal &rhs) { 
      name = rhs.name; val = rhs.val; }
   NamedVal(IOParamBlock *parent, const char *varName, 
      const T& initialVal=T()) : name(varName), val(initialVal)
   { parent->AddVar(this); }

   // conversion operators to make this class look like T
   operator T & ()    { return val; }
   T* operator & ()   { return &val; }
   // allow assignment of a value of type T
   NamedVal<T> & operator = (const T& rhs) {
      val=rhs; return *this; }
   const char *Name() { return name.c_str(); }

   virtual void Write(SimpleDB &db, const char *section) {
      char buf[100]; std::strstream strs;
      strs << val; strs >> buf; db.Write(section, Name(), buf);
   }
   virtual void Read(SimpleDB &db, const char *section) {
      char buf[100]; db.Read(section, Name(), buf, 100);
      std::strstream strs; strs << buf; strs >> val;
   }
};

// declare a named variable
#define DECL_NAMED_VAL(type,name) NamedVal<type> name
// define, construct, allocate a named variable
#define DEF_NAMED_VAL(type,name) NamedVal<type> name(#name)
#define DEF_NAMED_VAL_I(type,name,val) \
   NamedVal<type> name(#name,val)
#define CONSTRUCT_NAMED_VAL(name) name(#name)
#define CONSTRUCT_NAMED_VAL_I(name, val) name(#name, val)
#define NEW_NAMED_VAL(type,name) name=new NamedVal<type>(#name)
#define NEW_NAMED_VAL_I(type,name,val) \
   name=new NamedVal<type> (#name,val)
// construct a NamedVal and insert into IOParamBlock
#define CONSTRUCT_AUTOIO_VAL(name, val) name(this, #name, val)

#endif //__NAMEDVAL_H__