Templates questions

A

Adrian

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;
}
 
A

amparikh

Adrian said:
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 ?
 
D

doug turnbull

Adrian said:
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.
 

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,769
Messages
2,569,580
Members
45,054
Latest member
TrimKetoBoost

Latest Threads

Top