Templates questions

Discussion in 'C++' started by Adrian, Nov 6, 2006.

  1. Adrian

    Adrian Guest

    I have some class to read and store options from a config file.

    I have a design which works for the basic types. What I want to add is an array
    like type. I am not sure how to define the Field Class specific template. What I
    tried doesnt work.

    I have included a cut down version of the code.

    TIA

    ------example.conf
    LogFile /usr/home/interlex/www/logs/access_log
    OutputDir /home/interlex/www/htdocs/weblogs
    PageType htm*
    PageType cgi
    PageType php
    test_int 3467
    test_float 3.143
    test_double 4.54675745
    test_bool true
    test_bool2 false

    ----------code

    #include <iostream>
    #include <fstream>
    #include <string>
    #include <map>
    #include <stdexcept>
    #include <cstdlib>
    #include <locale>
    #include <vector>

    class FieldBase
    {
    public:
    virtual ~FieldBase() {};
    virtual void Set(const std::string &s)=0;
    virtual FieldBase &operator=(const std::string &s)=0;
    private:
    };

    template<class T>
    class Field: public FieldBase
    {
    public:
    void Set(const std::string &s);
    virtual Field &operator=(const std::string &s);
    T Get() const { return T(data); };
    ~Field() {};
    private:
    T data;
    };

    template<>
    class Field<int> : public FieldBase
    {
    public:
    void Set(const std::string &s)
    {
    data=std::atoi(s.c_str());
    };

    Field &operator=(const std::string &s)
    {
    Set(s);
    return *this;
    };
    int Get() const { return int(data); };
    ~Field() {};
    private:
    int data;
    };

    template<>
    class Field<std::string>: public FieldBase
    {
    public:
    void Set(const std::string &s)
    {
    data=s;
    };

    Field &operator=(const std::string &s)
    {
    Set(s);
    return *this;
    };
    std::string Get() const { return std::string(data); };
    ~Field() {};
    private:
    std::string data;
    };

    template<>
    class Field<float>: public FieldBase
    {
    public:
    void Set(const std::string &s)
    {
    data=std::atof(s.c_str());
    };
    Field &operator=(const std::string &s)
    {
    Set(s);
    return *this;
    };
    float Get() const { return float(data); };
    ~Field() {};
    private:
    float data;
    };


    template<>
    class Field<double>: public FieldBase
    {
    public:
    void Set(const std::string &s)
    {
    data=std::atof(s.c_str());
    };
    Field &operator=(const std::string &s)
    {
    Set(s);
    return *this;
    };
    double Get() const { return double(data); };
    ~Field() {};
    private:
    double data;
    };

    template<>
    class Field<bool>: public FieldBase
    {
    public:
    void Set(const std::string &s)
    {
    std::string temp=s;
    std::string::iterator i=temp.begin();
    while(i!=temp.end())
    {
    (*i)=std::toupper(*i);
    ++i;
    }

    data=temp=="TRUE";
    };
    Field &operator=(const std::string &s)
    {
    Set(s);
    return *this;
    };
    bool Get() const { return bool(data); };
    ~Field() {};
    private:
    bool data;
    };
    #if 0
    template<>
    class Field<std::vector<std::string> >: public FieldBase
    {
    public:
    void Set(const std::string &s)
    {
    data.push_back(s);
    }

    Field &operator=(const std::string &s)
    {
    Set(s);
    return *this;
    }

    std::vector<std::string> Get() const {return data;};
    ~Field() {};
    private:
    std::vector<std::string> data;
    }
    #endif

    class Config
    {
    public:
    virtual ~Config();
    void parse(void);

    template<class T>
    T Get(const std::string &f) const
    {
    Fields_t::const_iterator i=fields_.find(f);
    if(i!=fields_.end())
    {
    try
    {
    const Field<T> &ptr=dynamic_cast<Field<T> &>(*i->second);
    return ptr.Get();
    }
    catch(...)
    {
    throw;
    }
    }
    throw std::runtime_error("Config field " + f + " does not exist");
    }

    template<class T>
    void AddField(const std::string &fieldname, bool required=true)
    {
    fields_[fieldname]=new Field<T>();
    }

    protected:
    Config(const std::string &file);

    private:
    typedef std::map<std::string, FieldBase *> Fields_t;
    void trim_(std::string &l);
    Fields_t fields_;
    std::string filename_;
    static const char comment_char_='#';
    };

    class ExampleConfig : public Config
    {
    public:
    ExampleConfig(const std::string &file);
    private:
    };

    Config::Config(const std::string &file)
    : filename_(file)
    {
    }

    Config::~Config()
    {
    for(Fields_t::iterator i=fields_.begin(); i!=fields_.end(); i++)
    {
    delete (i->second);
    }
    }

    void Config::parse(void)
    {
    std::ifstream in;
    std::string keyword;
    std::string value;
    std::string line;

    in.open(filename_.c_str());
    if(!in.is_open())
    {
    throw std::runtime_error("Could not open file: " + filename_);
    }

    while(getline(in, line))
    {
    trim_(line);
    if(line[0]==comment_char_ || line.empty())
    {
    continue;
    }
    keyword=line.substr(0, line.find_first_of(" \t"));
    line.erase(0, keyword.length());
    value=line.substr(line.find_first_not_of(" \t"));

    FieldBase *ptr=fields_[keyword];
    if(ptr)
    {
    ptr->Set(value);
    }
    }
    }

    void Config::trim_(std::string &l)
    {
    const char *white_space=" \t";
    l.erase(0, l.find_first_not_of(white_space));
    l.erase(l.find_last_not_of(white_space)+1);
    }


    ExampleConfig::ExampleConfig(const std::string &file)
    :Config(file)
    {
    AddField<std::string>("OutputDir");
    AddField<std::string>("LogFile");
    AddField<std::string>("PageType");
    // I want to be able to do something like below
    // AddField<std::vector<std::string> >("PageType");
    AddField<float>("test_float");
    AddField<double>("test_double");
    AddField<bool>("test_bool");
    AddField<bool>("test_bool2");
    AddField<int>("test_int");

    parse();
    }

    int main(int argc, char *argv[])
    {
    try
    {
    ExampleConfig config("example.conf");

    std::cout << config.Get<std::string>("LogFile") << std::endl;
    std::cout << config.Get<std::string>("OutputDir") << std::endl;
    std::cout << config.Get<std::string>("PageType") << std::endl;
    // I want to be able to do something like below
    // std::cout << config.Get<std::vector<std::string> >("PageType")[0] << std::endl;
    std::cout << config.Get<int>("test_int") << std::endl;
    std::cout << config.Get<float>("test_float") << std::endl;
    std::cout << config.Get<double>("test_double") << std::endl;
    std::cout << config.Get<bool>("test_bool") << std::endl;
    std::cout << config.Get<bool>("test_bool2") << std::endl;
    std::cout << config.Get<std::string>("HideURL") << std::endl;
    }
    catch(const std::exception &e)
    {
    std::cerr << e.what() << std::endl;
    }

    return 0;
    }



    --

    Adrian

    Think you know a language? Post to comp.lang... and find out!
     
    Adrian, Nov 6, 2006
    #1
    1. Advertising

  2. Adrian

    Guest

    Adrian wrote:
    > I have some class to read and store options from a config file.
    >
    > I have a design which works for the basic types. What I want to add is an array
    > like type. I am not sure how to define the Field Class specific template. What I
    > tried doesnt work.
    >
    > I have included a cut down version of the code.
    >
    > TIA
    >
    > ------example.conf
    > LogFile /usr/home/interlex/www/logs/access_log
    > OutputDir /home/interlex/www/htdocs/weblogs
    > PageType htm*
    > PageType cgi
    > PageType php
    > test_int 3467
    > test_float 3.143
    > test_double 4.54675745
    > test_bool true
    > test_bool2 false
    >
    > ----------code
    >
    > #include <iostream>
    > #include <fstream>
    > #include <string>
    > #include <map>
    > #include <stdexcept>
    > #include <cstdlib>
    > #include <locale>
    > #include <vector>
    >
    > class FieldBase
    > {
    > public:
    > virtual ~FieldBase() {};
    > virtual void Set(const std::string &s)=0;
    > virtual FieldBase &operator=(const std::string &s)=0;
    > private:
    > };
    >
    > template<class T>
    > class Field: public FieldBase
    > {
    > public:
    > void Set(const std::string &s);
    > virtual Field &operator=(const std::string &s);
    > T Get() const { return T(data); };
    > ~Field() {};
    > private:
    > T data;
    > };
    >
    > template<>
    > class Field<int> : public FieldBase
    > {
    > public:
    > void Set(const std::string &s)
    > {
    > data=std::atoi(s.c_str());
    > };
    >
    > Field &operator=(const std::string &s)
    > {
    > Set(s);
    > return *this;
    > };
    > int Get() const { return int(data); };
    > ~Field() {};
    > private:
    > int data;
    > };
    >
    > template<>
    > class Field<std::string>: public FieldBase
    > {
    > public:
    > void Set(const std::string &s)
    > {
    > data=s;
    > };
    >
    > Field &operator=(const std::string &s)
    > {
    > Set(s);
    > return *this;
    > };
    > std::string Get() const { return std::string(data); };
    > ~Field() {};
    > private:
    > std::string data;
    > };
    >
    > template<>
    > class Field<float>: public FieldBase
    > {
    > public:
    > void Set(const std::string &s)
    > {
    > data=std::atof(s.c_str());
    > };
    > Field &operator=(const std::string &s)
    > {
    > Set(s);
    > return *this;
    > };
    > float Get() const { return float(data); };
    > ~Field() {};
    > private:
    > float data;
    > };
    >
    >
    > template<>
    > class Field<double>: public FieldBase
    > {
    > public:
    > void Set(const std::string &s)
    > {
    > data=std::atof(s.c_str());
    > };
    > Field &operator=(const std::string &s)
    > {
    > Set(s);
    > return *this;
    > };
    > double Get() const { return double(data); };
    > ~Field() {};
    > private:
    > double data;
    > };
    >
    > template<>
    > class Field<bool>: public FieldBase
    > {
    > public:
    > void Set(const std::string &s)
    > {
    > std::string temp=s;
    > std::string::iterator i=temp.begin();
    > while(i!=temp.end())
    > {
    > (*i)=std::toupper(*i);
    > ++i;
    > }
    >
    > data=temp=="TRUE";
    > };
    > Field &operator=(const std::string &s)
    > {
    > Set(s);
    > return *this;
    > };
    > bool Get() const { return bool(data); };
    > ~Field() {};
    > private:
    > bool data;
    > };
    > #if 0
    > template<>
    > class Field<std::vector<std::string> >: public FieldBase
    > {
    > public:
    > void Set(const std::string &s)
    > {
    > data.push_back(s);
    > }
    >
    > Field &operator=(const std::string &s)
    > {
    > Set(s);
    > return *this;
    > }
    >
    > std::vector<std::string> Get() const {return data;};
    > ~Field() {};
    > private:
    > std::vector<std::string> data;
    > }
    > #endif
    >
    > class Config
    > {
    > public:
    > virtual ~Config();
    > void parse(void);
    >
    > template<class T>
    > T Get(const std::string &f) const
    > {
    > Fields_t::const_iterator i=fields_.find(f);
    > if(i!=fields_.end())
    > {
    > try
    > {
    > const Field<T> &ptr=dynamic_cast<Field<T> &>(*i->second);
    > return ptr.Get();
    > }
    > catch(...)
    > {
    > throw;
    > }
    > }
    > throw std::runtime_error("Config field " + f + " does not exist");
    > }
    >
    > template<class T>
    > void AddField(const std::string &fieldname, bool required=true)
    > {
    > fields_[fieldname]=new Field<T>();
    > }
    >
    > protected:
    > Config(const std::string &file);
    >
    > private:
    > typedef std::map<std::string, FieldBase *> Fields_t;
    > void trim_(std::string &l);
    > Fields_t fields_;
    > std::string filename_;
    > static const char comment_char_='#';
    > };
    >
    > class ExampleConfig : public Config
    > {
    > public:
    > ExampleConfig(const std::string &file);
    > private:
    > };
    >
    > Config::Config(const std::string &file)
    > : filename_(file)
    > {
    > }
    >
    > Config::~Config()
    > {
    > for(Fields_t::iterator i=fields_.begin(); i!=fields_.end(); i++)
    > {
    > delete (i->second);
    > }
    > }
    >
    > void Config::parse(void)
    > {
    > std::ifstream in;
    > std::string keyword;
    > std::string value;
    > std::string line;
    >
    > in.open(filename_.c_str());
    > if(!in.is_open())
    > {
    > throw std::runtime_error("Could not open file: " + filename_);
    > }
    >
    > while(getline(in, line))
    > {
    > trim_(line);
    > if(line[0]==comment_char_ || line.empty())
    > {
    > continue;
    > }
    > keyword=line.substr(0, line.find_first_of(" \t"));
    > line.erase(0, keyword.length());
    > value=line.substr(line.find_first_not_of(" \t"));
    >
    > FieldBase *ptr=fields_[keyword];
    > if(ptr)
    > {
    > ptr->Set(value);
    > }
    > }
    > }
    >
    > void Config::trim_(std::string &l)
    > {
    > const char *white_space=" \t";
    > l.erase(0, l.find_first_not_of(white_space));
    > l.erase(l.find_last_not_of(white_space)+1);
    > }
    >
    >
    > ExampleConfig::ExampleConfig(const std::string &file)
    > :Config(file)
    > {
    > AddField<std::string>("OutputDir");
    > AddField<std::string>("LogFile");
    > AddField<std::string>("PageType");
    > // I want to be able to do something like below
    > // AddField<std::vector<std::string> >("PageType");
    > AddField<float>("test_float");
    > AddField<double>("test_double");
    > AddField<bool>("test_bool");
    > AddField<bool>("test_bool2");
    > AddField<int>("test_int");
    >
    > parse();
    > }
    >
    > int main(int argc, char *argv[])
    > {
    > try
    > {
    > ExampleConfig config("example.conf");
    >
    > std::cout << config.Get<std::string>("LogFile") << std::endl;
    > std::cout << config.Get<std::string>("OutputDir") << std::endl;
    > std::cout << config.Get<std::string>("PageType") << std::endl;
    > // I want to be able to do something like below
    > // std::cout << config.Get<std::vector<std::string> >("PageType")[0] << std::endl;
    > std::cout << config.Get<int>("test_int") << std::endl;
    > std::cout << config.Get<float>("test_float") << std::endl;
    > std::cout << config.Get<double>("test_double") << std::endl;
    > std::cout << config.Get<bool>("test_bool") << std::endl;
    > std::cout << config.Get<bool>("test_bool2") << std::endl;
    > std::cout << config.Get<std::string>("HideURL") << std::endl;
    > }
    > catch(const std::exception &e)
    > {
    > std::cerr << e.what() << std::endl;
    > }
    >
    > return 0;
    > }
    >
    >
    >
    > --
    >
    > Adrian
    >
    > Think you know a language? Post to comp.lang... and find out!


    the code compiles fine with VS 2005. What compiler are you using ?
     
    , Nov 6, 2006
    #2
    1. Advertising

  3. Adrian

    Adrian Guest

    wrote:
    > the code compiles fine with VS 2005. What compiler are you using ?

    gcc 3.4.2

    Its the bits that are commented out that wont compile well.


    --

    Adrian

    Think you know a language? Post to comp.lang... and find out!
     
    Adrian, Nov 7, 2006
    #3
  4. Adrian wrote:
    > wrote:
    > > the code compiles fine with VS 2005. What compiler are you using ?

    > gcc 3.4.2
    >
    > Its the bits that are commented out that wont compile well.
    >
    >
    > --
    >
    > Adrian
    >
    > Think you know a language? Post to comp.lang... and find out!


    We use gcc 3.4.3, I find the template support highly lacking compared
    to the latest Visual Studio. I have had similar experiences of template
    code working in Visual Studio and not gcc/g++. Maybe the latest gcc
    (4.x) resolves some of these issues.
     
    doug turnbull, Nov 7, 2006
    #4
    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. Fred
    Replies:
    1
    Views:
    635
    Neredbojias
    Sep 26, 2005
  2. John Harrison

    using templates in templates

    John Harrison, Jul 31, 2003, in forum: C++
    Replies:
    8
    Views:
    405
    Torsten Curdt
    Jul 31, 2003
  3. JKop
    Replies:
    3
    Views:
    526
  4. Tom McCallum

    Templates within templates

    Tom McCallum, Aug 4, 2004, in forum: C++
    Replies:
    2
    Views:
    382
    tom_usenet
    Aug 4, 2004
  5. recover
    Replies:
    2
    Views:
    863
    recover
    Jul 25, 2006
Loading...

Share This Page