C++Talk.NET Forum Index C++Talk.NET
C++ language newsgroups
 
Archives   FAQFAQ   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

Can I have std::vector store these subclasses mixed?

 
Post new topic   Reply to topic    C++Talk.NET Forum Index -> C++ language (comp.lang.c++)
View previous topic :: View next topic  
Author Message
Eric Lilja
Guest





PostPosted: Sat Feb 26, 2005 9:35 am    Post subject: Can I have std::vector store these subclasses mixed? Reply with quote



Hello, in my program I am reading a text file that has format:
option=value
There are several types of options and they expect values of different types
(mostly strings or integers). I made a templated base class Option and had
my different options derive from Option instantiated for their type (i.e.,
class LongOption inherits publicly from Option<long>). I selected this
approach because I wanted a uniform interface for obtaining the type and
value of a given option. I came up with the following class tree for testing
purposes:
template <typename T>
class Option
{
public:
enum OptionType
{
LONG,
STRING
};

Option(const std::string& name)
:
m_name(name),
m_not_set(true) {}

virtual ~Option() {}

T get_value() const
{
if(m_not_set)
throw;

return m_value;
}

void set_value(const T& value)
{
m_not_set = false;

m_value = value;
}

virtual OptionType get_type() const = 0;

private:
std::string m_name;
bool m_not_set;
T m_value;
};

class LongOption : public Option<long>
{
public:
LongOption(const std::string& name)
:
Option<long>(name) {}

virtual OptionType get_type() const
{
return STRING;
}
};

class StringOption : public Option<std::string>
{
public:
StringOption(const std::string& name)
:
Option<std::string>(name) {}

virtual OptionType get_type() const
{
return LONG;
}
};

That seems to compile, but I cannot do:
std::vector<Option*> options(11);
options[0] = new StringOption("Name=");
The compiler complains:
$ make gccmain
g++ gccmain.cpp -o gccmain
gccmain.cpp: In function `int main()':
gccmain.cpp:6: error: use of class template `template<class T> class Option'
as expression
gccmain.cpp:6: error: parse error before `>' token
gccmain.cpp:8: error: `options' undeclared (first use this function)
gccmain.cpp:8: error: (Each undeclared identifier is reported only once for
each function it appears in.)
make: *** [gccmain] Error 1

Not being able to store my different options in the same container makes
reading the file with options a lot messier...are their any ways to solve
this? I'm not very good at templates so I've certainly made a number of
silly mistakes.

/ Eric


Back to top
Rolf Magnus
Guest





PostPosted: Sat Feb 26, 2005 10:50 am    Post subject: Re: Can I have std::vector store these subclasses mixed? Reply with quote



Eric Lilja wrote:

Quote:
Hello, in my program I am reading a text file that has format:
option=value
There are several types of options and they expect values of different
types (mostly strings or integers). I made a templated base class Option
and had my different options derive from Option instantiated for their
type (i.e., class LongOption inherits publicly from Option<long>). I
selected this approach because I wanted a uniform interface for obtaining
the type and value of a given option. I came up with the following class
tree for testing purposes:
template <typename T
class Option
{
public:
enum OptionType
{
LONG,
STRING
};

This enum must be changed whenever you add another derived type. I'd use
typeinfo instead.

Quote:

Option(const std::string& name)
:
m_name(name),
m_not_set(true) {}

virtual ~Option() {}

T get_value() const
{
if(m_not_set)
throw;

throw what?

Quote:

return m_value;
}

void set_value(const T& value)
{
m_not_set = false;

m_value = value;
}

virtual OptionType get_type() const = 0;

private:
std::string m_name;
bool m_not_set;
T m_value;
};

class LongOption : public Option {
public:
LongOption(const std::string& name)
:
Option
virtual OptionType get_type() const
{
return STRING;
}
};

I don't really think you need to derive for each type if you use typeinfo.
I'll present an example of what I mean below.

Quote:

class StringOption : public Option<std::string
{
public:
StringOption(const std::string& name)
:
Option
virtual OptionType get_type() const
{
return LONG;
}
};

That seems to compile, but I cannot do:
std::vector<Option*> options(11);

Option is a template, not a type. Therefore, you cannot create a vector of
Option pointers.

Quote:
options[0] = new StringOption("Name=");
The compiler complains:
$ make gccmain
g++ gccmain.cpp -o gccmain
gccmain.cpp: In function `int main()':
gccmain.cpp:6: error: use of class template `template<class T> class
Option' as expression
gccmain.cpp:6: error: parse error before `>' token
gccmain.cpp:8: error: `options' undeclared (first use this function)
gccmain.cpp:8: error: (Each undeclared identifier is reported only once
for
each function it appears in.)
make: *** [gccmain] Error 1

Not being able to store my different options in the same container makes
reading the file with options a lot messier...are their any ways to solve
this?

Yes. Make a non-templated base class and derive your Option template from
it. Then store pointers to that base class in your container.

Quote:
I'm not very good at templates so I've certainly made a number of
silly mistakes.


class OptionBase
{
public:
OptionBase(const std::string& name)
: m_name(name),
m_not_set(true)
{
}
virtual std::typeinfo get_type() const = 0;
virtual ~OptionBase() {}

private:
std::string m_name;
bool m_not_set;
};

template <typename T>
class Option : public OptionBase
{
public:
Option(const std::string& name)
: OptionBase(name)
{}

T get_value() const
{
if(m_not_set)
throw SomeException();

return m_value;
}

void set_value(const T& value)
{
m_not_set = false;

m_value = value;
}

virtual std::typeinfo get_type() const
{
return typeid(T);
}

private:
T m_value;
};

//Don't need to derive for each type anymore - a typedef is sufficient
typedef Option<Long> LongOption;
typedef Option<std::string> StringOption;

//...
std::vector<OptionBase*> options(11);
options[0] = new StringOption("Name=");

//And to test for the type:
if (options[0]->get_type() == typeid(std::string))
{
//we have a string
}

Another thing you might be interested in is boost::any. See
http://www.boost.org/doc/html/any.html


Back to top
Eric Lilja
Guest





PostPosted: Sat Feb 26, 2005 11:18 am    Post subject: Re: Can I have std::vector store these subclasses mixed? Reply with quote




"Rolf Magnus" <ramagnus (AT) t-online (DOT) de> wrote

Quote:
Eric Lilja wrote:

Hello, in my program I am reading a text file that has format:
option=value
There are several types of options and they expect values of different
types (mostly strings or integers). I made a templated base class Option
and had my different options derive from Option instantiated for their
type (i.e., class LongOption inherits publicly from Option<long>). I
selected this approach because I wanted a uniform interface for obtaining
the type and value of a given option. I came up with the following class
tree for testing purposes:
template <typename T
class Option
{
public:
enum OptionType
{
LONG,
STRING
};

This enum must be changed whenever you add another derived type. I'd use
typeinfo instead.


Option(const std::string& name)
:
m_name(name),
m_not_set(true) {}

virtual ~Option() {}

T get_value() const
{
if(m_not_set)
throw;

throw what?


return m_value;
}

void set_value(const T& value)
{
m_not_set = false;

m_value = value;
}

virtual OptionType get_type() const = 0;

private:
std::string m_name;
bool m_not_set;
T m_value;
};

class LongOption : public Option {
public:
LongOption(const std::string& name)
:
Option
virtual OptionType get_type() const
{
return STRING;
}
};

I don't really think you need to derive for each type if you use typeinfo.
I'll present an example of what I mean below.


class StringOption : public Option<std::string
{
public:
StringOption(const std::string& name)
:
Option
virtual OptionType get_type() const
{
return LONG;
}
};

That seems to compile, but I cannot do:
std::vector<Option*> options(11);

Option is a template, not a type. Therefore, you cannot create a vector of
Option pointers.

options[0] = new StringOption("Name=");
The compiler complains:
$ make gccmain
g++ gccmain.cpp -o gccmain
gccmain.cpp: In function `int main()':
gccmain.cpp:6: error: use of class template `template<class T> class
Option' as expression
gccmain.cpp:6: error: parse error before `>' token
gccmain.cpp:8: error: `options' undeclared (first use this function)
gccmain.cpp:8: error: (Each undeclared identifier is reported only once
for
each function it appears in.)
make: *** [gccmain] Error 1

Not being able to store my different options in the same container makes
reading the file with options a lot messier...are their any ways to solve
this?

Yes. Make a non-templated base class and derive your Option template from
it. Then store pointers to that base class in your container.

I'm not very good at templates so I've certainly made a number of
silly mistakes.


class OptionBase
{
public:
OptionBase(const std::string& name)
: m_name(name),
m_not_set(true)
{
}
virtual std::typeinfo get_type() const = 0;
virtual ~OptionBase() {}

private:
std::string m_name;
bool m_not_set;
};

template <typename T
class Option : public OptionBase
{
public:
Option(const std::string& name)
: OptionBase(name)
{}

T get_value() const
{
if(m_not_set)
throw SomeException();

return m_value;
}

void set_value(const T& value)
{
m_not_set = false;

m_value = value;
}

virtual std::typeinfo get_type() const
{
return typeid(T);
}

private:
T m_value;
};

//Don't need to derive for each type anymore - a typedef is sufficient
typedef Option typedef Option<std::string> StringOption;

//...
std::vector<OptionBase*> options(11);
options[0] = new StringOption("Name=");

//And to test for the type:
if (options[0]->get_type() == typeid(std::string))
{
//we have a string
}

Another thing you might be interested in is boost::any. See
http://www.boost.org/doc/html/any.html


Very nice, Rolf! I will try out your code as soon as I've showered & shaved,
looks real nice! Thank you for such a detailed response.

/ Eric



Back to top
Eric Lilja
Guest





PostPosted: Sat Feb 26, 2005 11:39 am    Post subject: Re: Can I have std::vector store these subclasses mixed? Reply with quote


"Eric Lilja" <ericliljaNoSpam (AT) yahoo (DOT) com> wrote

Quote:

"Rolf Magnus" <ramagnus (AT) t-online (DOT) de> wrote in message
news:cvpjvl$jrl$00$1 (AT) news (DOT) t-online.com...
Eric Lilja wrote:

Hello, in my program I am reading a text file that has format:
option=value
There are several types of options and they expect values of different
types (mostly strings or integers). I made a templated base class Option
and had my different options derive from Option instantiated for their
type (i.e., class LongOption inherits publicly from Option<long>). I
selected this approach because I wanted a uniform interface for
obtaining
the type and value of a given option. I came up with the following class
tree for testing purposes:
template <typename T
class Option
{
public:
enum OptionType
{
LONG,
STRING
};

This enum must be changed whenever you add another derived type. I'd use
typeinfo instead.


Option(const std::string& name)
:
m_name(name),
m_not_set(true) {}

virtual ~Option() {}

T get_value() const
{
if(m_not_set)
throw;

throw what?


return m_value;
}

void set_value(const T& value)
{
m_not_set = false;

m_value = value;
}

virtual OptionType get_type() const = 0;

private:
std::string m_name;
bool m_not_set;
T m_value;
};

class LongOption : public Option {
public:
LongOption(const std::string& name)
:
Option
virtual OptionType get_type() const
{
return STRING;
}
};

I don't really think you need to derive for each type if you use
typeinfo.
I'll present an example of what I mean below.


class StringOption : public Option<std::string
{
public:
StringOption(const std::string& name)
:
Option
virtual OptionType get_type() const
{
return LONG;
}
};

That seems to compile, but I cannot do:
std::vector<Option*> options(11);

Option is a template, not a type. Therefore, you cannot create a vector
of
Option pointers.

options[0] = new StringOption("Name=");
The compiler complains:
$ make gccmain
g++ gccmain.cpp -o gccmain
gccmain.cpp: In function `int main()':
gccmain.cpp:6: error: use of class template `template<class T> class
Option' as expression
gccmain.cpp:6: error: parse error before `>' token
gccmain.cpp:8: error: `options' undeclared (first use this function)
gccmain.cpp:8: error: (Each undeclared identifier is reported only once
for
each function it appears in.)
make: *** [gccmain] Error 1

Not being able to store my different options in the same container makes
reading the file with options a lot messier...are their any ways to
solve
this?

Yes. Make a non-templated base class and derive your Option template from
it. Then store pointers to that base class in your container.

I'm not very good at templates so I've certainly made a number of
silly mistakes.


class OptionBase
{
public:
OptionBase(const std::string& name)
: m_name(name),
m_not_set(true)
{
}
virtual std::typeinfo get_type() const = 0;
virtual ~OptionBase() {}

private:
std::string m_name;
bool m_not_set;
};

template <typename T
class Option : public OptionBase
{
public:
Option(const std::string& name)
: OptionBase(name)
{}

T get_value() const
{
if(m_not_set)
throw SomeException();

return m_value;
}

void set_value(const T& value)
{
m_not_set = false;

m_value = value;
}

virtual std::typeinfo get_type() const
{
return typeid(T);
}

private:
T m_value;
};

//Don't need to derive for each type anymore - a typedef is sufficient
typedef Option typedef Option<std::string> StringOption;

//...
std::vector<OptionBase*> options(11);
options[0] = new StringOption("Name=");

//And to test for the type:
if (options[0]->get_type() == typeid(std::string))
{
//we have a string
}

Another thing you might be interested in is boost::any. See
http://www.boost.org/doc/html/any.html


Very nice, Rolf! I will try out your code as soon as I've showered &
shaved, looks real nice! Thank you for such a detailed response.

/ Eric


Heh, I couldn't wait to try the code out..I'm having some problems...first I
had to change std::typeinfo to std::type_info, guess that was just a simple
typo on your part (happens all the time for me). But I'm still having
problems with the get_type() function. The code is:

class OptionBase
{
public:
OptionBase(const std::string& name)
:
m_name(name),
m_not_set(true) {}

virtual ~OptionBase() {}

virtual std::type_info get_type() const = 0;

private:
std::string m_name;
bool m_not_set;
};

template<typename T>
class Option : public OptionBase
{
public:
Option(const std::string& name)
:
OptionBase(name) {}

virtual std::type_info get_type() const
{
return typeid(T);
}

T get_value() const
{
if(m_not_set)
throw;
return m_value;
}

void set_value(const T& value)
{
m_value = value;
m_not_set = false;
}

private:
T m_value;
};

typedef Option<std::string> StringOption;

int main()
{
std::vector<OptionBase*> options(11);

options[0] = new StringOption("duh");

return 0;
}

and the error is:
/usr/include/c++/3.3.3/typeinfo: In member function `std::type_info
Option<T>::get_type() const [with T = std::string]':
gccmain.cpp:8: instantiated from here
/usr/include/c++/3.3.3/typeinfo:75: error: `std::type_info::type_info(const
std::type_info&)' is private
option.hpp:38: error: within this context
make: *** [gccmain] Error 1

What am I doing wrong? I must say that I have never used type_info before.

/ Eric



Back to top
Eric Lilja
Guest





PostPosted: Sat Feb 26, 2005 12:18 pm    Post subject: Re: Can I have std::vector store these subclasses mixed? Reply with quote


"Eric Lilja" <ericliljaNoSpam (AT) yahoo (DOT) com> wrote

Quote:

"Eric Lilja" <ericliljaNoSpam (AT) yahoo (DOT) com> wrote in message
news:cvplt7$240$1 (AT) news (DOT) island.liu.se...

"Rolf Magnus" <ramagnus (AT) t-online (DOT) de> wrote in message
news:cvpjvl$jrl$00$1 (AT) news (DOT) t-online.com...
Eric Lilja wrote:

Hello, in my program I am reading a text file that has format:
option=value
There are several types of options and they expect values of different
types (mostly strings or integers). I made a templated base class
Option
and had my different options derive from Option instantiated for their
type (i.e., class LongOption inherits publicly from Option<long>). I
selected this approach because I wanted a uniform interface for
obtaining
the type and value of a given option. I came up with the following
class
tree for testing purposes:
template <typename T
class Option
{
public:
enum OptionType
{
LONG,
STRING
};

This enum must be changed whenever you add another derived type. I'd use
typeinfo instead.


Option(const std::string& name)
:
m_name(name),
m_not_set(true) {}

virtual ~Option() {}

T get_value() const
{
if(m_not_set)
throw;

throw what?


return m_value;
}

void set_value(const T& value)
{
m_not_set = false;

m_value = value;
}

virtual OptionType get_type() const = 0;

private:
std::string m_name;
bool m_not_set;
T m_value;
};

class LongOption : public Option {
public:
LongOption(const std::string& name)
:
Option
virtual OptionType get_type() const
{
return STRING;
}
};

I don't really think you need to derive for each type if you use
typeinfo.
I'll present an example of what I mean below.


class StringOption : public Option<std::string
{
public:
StringOption(const std::string& name)
:
Option
virtual OptionType get_type() const
{
return LONG;
}
};

That seems to compile, but I cannot do:
std::vector<Option*> options(11);

Option is a template, not a type. Therefore, you cannot create a vector
of
Option pointers.

options[0] = new StringOption("Name=");
The compiler complains:
$ make gccmain
g++ gccmain.cpp -o gccmain
gccmain.cpp: In function `int main()':
gccmain.cpp:6: error: use of class template `template<class T> class
Option' as expression
gccmain.cpp:6: error: parse error before `>' token
gccmain.cpp:8: error: `options' undeclared (first use this function)
gccmain.cpp:8: error: (Each undeclared identifier is reported only once
for
each function it appears in.)
make: *** [gccmain] Error 1

Not being able to store my different options in the same container
makes
reading the file with options a lot messier...are their any ways to
solve
this?

Yes. Make a non-templated base class and derive your Option template
from
it. Then store pointers to that base class in your container.

I'm not very good at templates so I've certainly made a number of
silly mistakes.


class OptionBase
{
public:
OptionBase(const std::string& name)
: m_name(name),
m_not_set(true)
{
}
virtual std::typeinfo get_type() const = 0;
virtual ~OptionBase() {}

private:
std::string m_name;
bool m_not_set;
};

template <typename T
class Option : public OptionBase
{
public:
Option(const std::string& name)
: OptionBase(name)
{}

T get_value() const
{
if(m_not_set)
throw SomeException();

return m_value;
}

void set_value(const T& value)
{
m_not_set = false;

m_value = value;
}

virtual std::typeinfo get_type() const
{
return typeid(T);
}

private:
T m_value;
};

//Don't need to derive for each type anymore - a typedef is sufficient
typedef Option typedef Option<std::string> StringOption;

//...
std::vector<OptionBase*> options(11);
options[0] = new StringOption("Name=");

//And to test for the type:
if (options[0]->get_type() == typeid(std::string))
{
//we have a string
}

Another thing you might be interested in is boost::any. See
http://www.boost.org/doc/html/any.html


Very nice, Rolf! I will try out your code as soon as I've showered &
shaved, looks real nice! Thank you for such a detailed response.

/ Eric


Heh, I couldn't wait to try the code out..I'm having some problems...first
I had to change std::typeinfo to std::type_info, guess that was just a
simple typo on your part (happens all the time for me). But I'm still
having problems with the get_type() function. The code is:

class OptionBase
{
public:
OptionBase(const std::string& name)
:
m_name(name),
m_not_set(true) {}

virtual ~OptionBase() {}

virtual std::type_info get_type() const = 0;

private:
std::string m_name;
bool m_not_set;
};

template<typename T
class Option : public OptionBase
{
public:
Option(const std::string& name)
:
OptionBase(name) {}

virtual std::type_info get_type() const
{
return typeid(T);
}

T get_value() const
{
if(m_not_set)
throw;
return m_value;
}

void set_value(const T& value)
{
m_value = value;
m_not_set = false;
}

private:
T m_value;
};

typedef Option
int main()
{
std::vector<OptionBase*> options(11);

options[0] = new StringOption("duh");

return 0;
}

and the error is:
/usr/include/c++/3.3.3/typeinfo: In member function `std::type_info
Option<T>::get_type() const [with T = std::string]':
gccmain.cpp:8: instantiated from here
/usr/include/c++/3.3.3/typeinfo:75: error:
`std::type_info::type_info(const
std::type_info&)' is private
option.hpp:38: error: within this context
make: *** [gccmain] Error 1

What am I doing wrong? I must say that I have never used type_info before.

/ Eric


Note: It compiles if I make get_type() a non-virtual member function of the
class Option (i.e., it doesn't appear in class ObjectBase at all). But that
removes the one function that made my OptionBase class an abstract base
class.

/ Eric



Back to top
Rolf Magnus
Guest





PostPosted: Sat Feb 26, 2005 12:36 pm    Post subject: Re: Can I have std::vector store these subclasses mixed? Reply with quote

Eric Lilja wrote:

Quote:
Heh, I couldn't wait to try the code out..I'm having some problems...first
I had to change std::typeinfo to std::type_info, guess that was just a
simple typo on your part (happens all the time for me).

Yes, it was. I haven't used type_info for a while, so I forgot the
underscore :-)

Quote:
and the error is:
/usr/include/c++/3.3.3/typeinfo: In member function `std::type_info
Option<T>::get_type() const [with T = std::string]':
gccmain.cpp:8: instantiated from here
/usr/include/c++/3.3.3/typeinfo:75: error:
`std::type_info::type_info(const
std::type_info&)' is private
option.hpp:38: error: within this context
make: *** [gccmain] Error 1

What am I doing wrong? I must say that I have never used type_info before.

Again, my error. std::type_info cannot be copied. Try returning it by
reference instead:

virtual const std::type_info& get_type() const
{
return typeid(T);
}


Back to top
Eric Lilja
Guest





PostPosted: Sat Feb 26, 2005 12:52 pm    Post subject: Re: Can I have std::vector store these subclasses mixed? Reply with quote


"Rolf Magnus" wrote:
Quote:
Eric Lilja wrote:

Heh, I couldn't wait to try the code out..I'm having some
problems...first
I had to change std::typeinfo to std::type_info, guess that was just a
simple typo on your part (happens all the time for me).

Yes, it was. I haven't used type_info for a while, so I forgot the
underscore :-)

and the error is:
/usr/include/c++/3.3.3/typeinfo: In member function `std::type_info
Option<T>::get_type() const [with T = std::string]':
gccmain.cpp:8: instantiated from here
/usr/include/c++/3.3.3/typeinfo:75: error:
`std::type_info::type_info(const
std::type_info&)' is private
option.hpp:38: error: within this context
make: *** [gccmain] Error 1

What am I doing wrong? I must say that I have never used type_info
before.

Again, my error. std::type_info cannot be copied. Try returning it by
reference instead:

virtual const std::type_info& get_type() const
{
return typeid(T);
}


Thanks Rolf, I finally made it compile and run without crashing. I had to
make m_not_set a protected (not private) member variable of class OptionBase
and I also removed the value variable from OptionBase. The only thing that
makes the class a bit cumbersome to use is that I have to find the proper
type and cast it to that before being able to call set_value() or
get_value() but I guess there's no way around that.

/ Eric



Back to top
Display posts from previous:   
Post new topic   Reply to topic    C++Talk.NET Forum Index -> C++ language (comp.lang.c++) All times are GMT
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2006 phpBB Group
SEO toolkit © 2004-2006 webmedic.