By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
445,898 Members | 2,039 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 445,898 IT Pros & Developers. It's quick & easy.

Templates questions

P: n/a
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::stringGet() const {return data;};
~Field() {};
private:
std::vector<std::stringdata;
}
#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!
Nov 6 '06 #1
Share this Question
Share on Google+
3 Replies


P: n/a

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::stringGet() const {return data;};
~Field() {};
private:
std::vector<std::stringdata;
}
#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 '06 #2

P: n/a
am******@gmail.com 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!
Nov 6 '06 #3

P: n/a

Adrian wrote:
am******@gmail.com 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.

Nov 7 '06 #4

This discussion thread is closed

Replies have been disabled for this discussion.