473,378 Members | 1,426 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,378 software developers and data experts.

trait technique?


Dear all,

I am not sure this is really a trait technique but I have some trouble
with the following. I would like to create a small object that carry
information about a value type (the template) and a convert member
function from string to the value type.

To do this I have defined

template <class _Tp>
struct type
{ };

and defined the specialisation I want like

template<>
struct type<char>
{
static string name() { return string("character"); }
static char convert(const string &value)
{
return *value.c_str();
}
};

template<>
struct type<int>
{
static string name() { return string("integer"); }
static int convert(const string &value)
{
return static_cast<int>(strtol(value.c_str(), 0, 10));
}
};

and so on....

Now I can define a test function

template<class T>
void test(const string & s)
{
cout << "s=" << s << "\ttype=" << type<T>::name() << " converted " <<
type<T>::convert(s) << endl;
}

and calls like

test<char>("c");
test<int>("2004");

works nicely.

Now I would like to extend to class type containers like vector

I tried

template <class T>
struct type< vector<T> >
{
static string name() { return string("vector<" + type<T>::name() + ">");
}
static vector<T> convert(const string &value)
{
// To implement for comma-separated T values
return vector<T>(0);
}
};
test< vector<int> >("1,2,3,4");

But my compiler is complaining. Any idea how to do that?
Sincerely,
Patrick

Jul 22 '05 #1
7 1540
Patrick Guio wrote:
I am not sure this is really a trait technique but I have some trouble
with the following. I would like to create a small object that carry
information about a value type (the template) and a convert member
function from string to the value type.

To do this I have defined

template <class _Tp>
struct type
{ };

and defined the specialisation I want like

template<>
struct type<char>
{
static string name() { return string("character"); }
static char convert(const string &value)
{
return *value.c_str();
}
};

template<>
struct type<int>
{
static string name() { return string("integer"); }
static int convert(const string &value)
{
return static_cast<int>(strtol(value.c_str(), 0, 10));
}
};

and so on....

Now I can define a test function

template<class T>
void test(const string & s)
{
cout << "s=" << s << "\ttype=" << type<T>::name() << " converted " <<
type<T>::convert(s) << endl;
}

and calls like

test<char>("c");
test<int>("2004");

works nicely.

Now I would like to extend to class type containers like vector

I tried

template <class T>
struct type< vector<T> >
{
static string name() { return string("vector<" + type<T>::name() +
">"); }
static vector<T> convert(const string &value)
{
// To implement for comma-separated T values
return vector<T>(0);
}
};
test< vector<int> >("1,2,3,4");

But my compiler is complaining. Any idea how to do that?


What is your compiler complaining about?

#include <vector>

template<class T> struct A { int a; };
template<class T> struct A<std::vector<T> > { char b; };

template<class T> A<T> bar(T t);

int main() {
std::vector<int> v;
bar(v).a; // error: A<vector<int> > has no member 'a'
bar(v).b; // OK
}

Victor
Jul 22 '05 #2
On Sat, 18 Dec 2004, Victor Bazarov wrote:

What is your compiler complaining about?

#include <vector>

template<class T> struct A { int a; };
template<class T> struct A<std::vector<T> > { char b; };

template<class T> A<T> bar(T t);

int main() {
std::vector<int> v;
bar(v).a; // error: A<vector<int> > has no member 'a'
bar(v).b; // OK
}

Victor


Oops, my fault, it actually works...
But I have another question: is there a way to have a container such as
map or vector that would contain pointers of different specialisations of
the template (a kind of polymorphic pointer for template class)?

Considering again the trait example

template <class _Tp>
struct type : typeClass
{
static string name();
static _Tp convert(string str);
};

template<>
struct type<bool>
{
// implementation
....
};

template<>
struct type<float>
{
// implementation
....
};

etc..

How would the second type map<int,?> myMap looks to allow the following

myMap[0] = type<bool>();
myMap[1] = type<float>();
Sincerely,

Patrick

Jul 22 '05 #3
Patrick Guio wrote:
Oops, my fault, it actually works... But I have another question: is
there a way to have a container such as map or vector that would contain
pointers of different specialisations of the template (a kind of
polymorphic pointer for template class)?
A container cannot contain different types. A vector of int will always
store ints. Since a class template is not a type (it is a family of
types), you cannot use it as an element type for a container.

template <class T> struct S;

std::vector< S > v; // illegal
std::vector< S* > v; // illegal

std::vector< S<int> > v; // ok
std::vector< S<int>* > v; // ok
Considering again the trait example

template <class _Tp>
struct type : typeClass
{
static string name();
static _Tp convert(string str);
};

template<>
struct type<bool>
{
// implementation
....
};

template<>
struct type<float>
{
// implementation
....
};

etc..

How would the second type map<int,?> myMap looks to allow the following

myMap[0] = type<bool>();
myMap[1] = type<float>();


Unfortunately, I cannot think of a solution. By using a common base
class for all these, you won't be able to have your convert() function
since its return type is a template argument (except by returning
Java-like pointers to an Object class, part of your framework, of which
would derive Integer and Bool classes). The thing is, C++ is very rigid
on types and fiddling with them can be difficult sometimes.

You could have

class Converter
{
public:
virtual std::string name() = 0;
};

class IntConverter : public Converter
{
public:
virtual std::string name() { ... }
};

class BoolConverter : public Converter
{
public:
virtual std::string name() { ... }
};

int main()
{
std::vector< Converter* > v;

v.push_back(new IntConverter);
v.push_back(new BoolConverter);

// don't forget to delete them
}

Perhaps libraries such as boost have something for you, but I don't have
other ideas.
Jonathan
Jul 22 '05 #4
Jonathan Mcdougall wrote:
Patrick Guio wrote:
Oops, my fault, it actually works... But I have another question: is
there a way to have a container such as map or vector that would
contain pointers of different specialisations of the template (a kind
of polymorphic pointer for template class)?

A container cannot contain different types. A vector of int will always
store ints. Since a class template is not a type (it is a family of
types), you cannot use it as an element type for a container.

template <class T> struct S;

std::vector< S > v; // illegal
std::vector< S* > v; // illegal

std::vector< S<int> > v; // ok
std::vector< S<int>* > v; // ok


This may or not be useful to the OP, but you can do this:

template <class T> struct S;

template <class T2>
struct S2
{
std::vector<S<T2> > v;
std::vector<S<T2>*> v2;
};
Jul 22 '05 #5
Patrick Guio wrote:
But I have another question: is
there a way to have a container such as map or vector that would contain
pointers of different specialisations of the template (a kind of
polymorphic pointer for template class)?
No - you're mixing compile time with runtime. How would you use the
type<T> object without knowing what T is?
Considering again the trait example

template <class _Tp>
struct type : typeClass
{
static string name();
static _Tp convert(string str);
};

template<>
struct type<bool>
{
// implementation
...
};

template<>
struct type<float>
{
// implementation
...
};

etc..

How would the second type map<int,?> myMap looks to allow the following

myMap[0] = type<bool>();
myMap[1] = type<float>();


map<int, typeClass> myMap;
myMap[0] = new type<bool>();
myMap[1] = new type<float>();

This assumes that typeClass looks like this:

class typeClass
{
public:
virtual ~typeClass(){}
virtual string name() const = 0;
//other type independent functions.
};

But what exactly are you doing?

Tom
Jul 22 '05 #6
On Mon, 20 Dec 2004, Tom Widmer wrote:

Hi Tom,
Considering again the trait example

template <class _Tp>
struct type : typeClass
{
static string name();
static _Tp convert(string str);
};

template<>
struct type<bool>
{
// implementation goes here
};

etc..

How would the second type map<int,?> myMap looks to allow the following

myMap[0] = type<bool>();
myMap[1] = type<float>();
map<int, typeClass> myMap;


Are you sure it is not map<int, typeClass*> ?
myMap[0] = new type<bool>();
myMap[1] = new type<float>();

This assumes that typeClass looks like this:

class typeClass
{
public:
virtual ~typeClass(){}
virtual string name() const = 0;
//other type independent functions.
};
I cannot compile as you say.
But what exactly are you doing?


I am trying to write a trait for a parser class. In principle I would like
to insert an options with a method which looks like

insert(optKey, type<optType>(), "optName", "optDescription", any(optVar))

OptKey is used as the first element of map<int, typeClass*> myMap.
The second data contains a pointer to the trait class for the type
optTYpe. It should contain

* the name of the type (for example real for float, double).
This is to be used for example for a --help option (as name())
* a convert algorithm from string to optType to be used when calling the
menber function parse(optKey, optVar)
* there might be need for another trait to test the domain of validity of
the option value (for example only positive integer)

* "optName" is the option name
* "optDescription" is a short description to be used for a --help option
* any(optVar) stores the current (default) value of the var in a any
container (boost).

Do you understand what I want to do? Any more ideas?

Sincerely,

Patrick

Jul 22 '05 #7
Patrick Guio wrote:
On Mon, 20 Dec 2004, Tom Widmer wrote:
Hi Tom,
Considering again the trait example

template <class _Tp>
struct type : typeClass
{
static string name();
static _Tp convert(string str);
};

template<>
struct type<bool>
{
// implementation goes here
};

etc..

How would the second type map<int,?> myMap looks to allow the following

myMap[0] = type<bool>();
myMap[1] = type<float>();
map<int, typeClass> myMap;


Are you sure it is not map<int, typeClass*> ?


It should be, or references. With references, you'll need to make sure
the objects exist for the life of the map. Since the safest way is with
heap-allocated objects, you'd be better off with pointers.
But what exactly are you doing?


I am trying to write a trait for a parser class. In principle I would like
to insert an options with a method which looks like

insert(optKey, type<optType>(), "optName", "optDescription", any(optVar))

OptKey is used as the first element of map<int, typeClass*> myMap.
The second data contains a pointer to the trait class for the type
optTYpe.


So it should be (asssuming optKey is or can be converted to int)

insert(optKey, new optType_type, ...);

optType_type should be class derived from type. You could use a factory
to make it easier. The map should look like

std::map<int, type*>

What yo need is run-time polymorphism and you can't achieve that with
templates, which requires all types to be known at compile-time.
It should contain

* the name of the type (for example real for float, double).
This is to be used for example for a --help option (as name())
That should be easy, since you can use a virtual function in class type
returning a std::string.
* a convert algorithm from string to optType to be used when calling the
menber function parse(optKey, optVar)
That will be impossible, though it would be nice. You will need to
design a framework à la Java with a base class (such as Object) and to
return objects by pointer/reference, wherever they are allocated (heap,
static...). You can use covariant return types to make your life easier.
* there might be need for another trait to test the domain of validity of
the option value (for example only positive integer)
That should be easy also, just use a virtual function.
* "optName" is the option name
* "optDescription" is a short description to be used for a --help option
* any(optVar) stores the current (default) value of the var in a any
container (boost).
Ok.
Do you understand what I want to do? Any more ideas?


C++ is not a language with which it is easy to play with types. The
kind of polymorphism you look for can only be implemented with a
hierarchy of classes.

1) Design a hierarchy of classes (Integer, Bool, Float...) all deriving
from Object.

Object has a pure virtual print(std::ostream&) or something and a
static key() function which returns an invalid key. Derived classes
should override that static function.

Add an global operator<< which takes a const Object&. Call print on
it.

class Object
{
public:
virtual ~Object();
virtual void print(std::ostream &stream) const = 0;
};

class Integer : public Object
{
private:
int value_;

public:
Integer(int value);
virtual void print(std::ostream &stream) const
};

....

2) Design a hierarchy of classes (IntegerConverter, BoolConverter,
FloatConverter...) all deriving from Converter. Converter will have
the following pure virtual functions :

. std::string name() const
returns the converter's name (such as "bool" or "integer").

. Object *convert(std::string s) ( Object* can be covariant )
parses the string and returns the corresponding object. return
0 if parsing failed.

. static Key key()
returns a unique number (Key could be an int). this function
may be a problem to maintain, just make sure what you return is
unique to the class.

class Converter
{
public:
typedef int Key;

public:
virtual std::string name() const = 0;
virtual Object *convert(std::string s) = 0;
static Key key() { return 0; }
};

class BoolConverter : public Converter
{
public:
virtual std::string name() const;
virtual Bool *convert(std::string s); // note : covariant

static Key key() { return unique_number; }
};

....

3) Make an Option class containing a Key and a name (such as "help" or
"an_option").

class Option
{
private:
Converter::Key key_;
std::string name_;

public:
Option(Converter::Key key, std::string name);
Converter::Key key() const;
std::string name() const
};

4) Make a Types class containing a map<Key, Converter*> which will have
all the converters (and will not forget to delete them :). Types
has something like get(Key k) which returns 0 or the correct
converter.

class Types
{
private:
typedef std::map<Converter::Key, Converter*> Map;
Map map_;

public:
Types();
~Types()

Converter *get(Converter::Key key);
void add(Converter::Key key, Converter *c);
};

5) Make a class Format which gets a reference to the Types object and
contains a vector of Options. Add a parse(std::string s) member
function. More on that one later.

class Format
{
private:
typedef std::vector<Option> Options;

Options options_;
Types &types_;

public:
Format(Types &types);
void add(Option o);

void parse(std::string what);
};

6) Have your main() function create a Types object and fill it with
converters. Then, create a Format object, giving it a reference to
the Types object, and fill it with options. Finally, give a string
to Format to parse it.

int main()
{
Types types;
types.add(BoolConverter::key(), new BoolConverter);
types.add(IntegerConverter::key(), new IntegerConverter);

Format format(types);
format.add(Option(BoolConverter::key(), "opt1"));
format.add(Option(IntegerConverter::key(), "opt2"));
format.add(Option(BoolConverter::key(), "opt3"));

format.parse("1 10 0");
}

Have Format::parse() fill a vector of std::string containing the tokens
of the given string. Iterate over all these tokens and the option list,
get the converter for that option and convert the token. You should get
an Object* or 0 if the conversion failed.

void Format::parse(std::string what)
{
typedef std::vector<std::string> Tokens;
Tokens tokens;

// tokenize 'what' into 'tokens'

Tokens::iterator token_itor = tokens.begin();
Options::iterator option_itor = options_.begin();

for ( ; token_itor != tokens.end() && option_itor !=
options_.end(); ++token_itor, ++option_itor)
{
Option *o = &*option_itor;
std::string t = *token_itor;

Converter *converter = types_.get(o->key());

if ( converter == 0 )
{
// type not found, that's a problem with the keys
continue;
}

Object *value = converter->convert(t);

if ( value != 0 )
{
std::cout << "got " << *value
<< " of type " << converter->name()
<< std::endl;
}
else
{
std::cout << "couldn't parse '" << t
<< "' to a " << converter->name()
<< std::endl;
}

delete value;
}
}

So with a string "1 10 0", you get

got true of type bool
got 10 of type integer
got false of type bool

and a string "1 a 0" you get

got true of type bool
couldn't parse 'a' to a integer
got false of type bool
I actually made the whole code (and it works quite well), so if you need
help with that design, I'll show you a bit more (but not too much :)

Jonathan
Jul 22 '05 #8

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

12
by: Trent | last post by:
I found an excellent technique in "Eric Meyers on CSS" that I thought some of you might be interested in. The technique is to use "debugging" styles to quickly see the layout of a page. For...
3
by: Jack Klein | last post by:
I'm looking for opinions on a C technique I, and others, have used successfully in the past. While some people swear by, apparently others swear at it. Assume a part of a program too large to...
0
by: deathyam | last post by:
Hi, I am writing an application in Excel 97 in which the users click a button and data is saved/read to and from an Access 97 database on the LAN. I am concerned about performance because there...
1
by: Bill Rubin | last post by:
The following code gives VC++ 7.1 compiler errors C2785 and C2912 template<class U> struct Trait {typedef double result;} template<class T> typename Trait<T>::result foo() template<> typename...
2
by: Niklas Norrthon | last post by:
I want to share a technique I recently have found to be useful to get around some obstacles that data protection can raise. Consider the following class: // foo.h #ifndef H_FOO #define H_FOO...
18
by: xahlee | last post by:
Last year, i've posted a tutorial and commentary about Python and Perl's sort function. (http://xahlee.org/perl-python/sort_list.html) In that article, i discussed a technique known among...
3
by: pragy | last post by:
Hey, can any one help me for writing a program of naive gauss elimintaion technique? It's a technique to solve system of simultaneous linear equations using matrix. thanks
2
by: Bob Alston | last post by:
Recently I have been helping a nonprofit modify a system built in Access, that they acquired from another nonprofit. I am doing this as a volunteer. I would like your perspective on two...
1
by: Ben Bacarisse | last post by:
cri@tiac.net (Richard Harter) writes: <snip> I too was going to mention the technique until I saw Eric's reply because in your sketch you said: | we have definitions like | | struct...
0
by: Faith0G | last post by:
I am starting a new it consulting business and it's been a while since I setup a new website. Is wordpress still the best web based software for hosting a 5 page website? The webpages will be...
0
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 3 Apr 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome former...
0
by: ryjfgjl | last post by:
In our work, we often need to import Excel data into databases (such as MySQL, SQL Server, Oracle) for data analysis and processing. Usually, we use database tools like Navicat or the Excel import...
0
by: Charles Arthur | last post by:
How do i turn on java script on a villaon, callus and itel keypad mobile phone
0
by: aa123db | last post by:
Variable and constants Use var or let for variables and const fror constants. Var foo ='bar'; Let foo ='bar';const baz ='bar'; Functions function $name$ ($parameters$) { } ...
0
by: ryjfgjl | last post by:
In our work, we often receive Excel tables with data in the same format. If we want to analyze these data, it can be difficult to analyze them because the data is spread across multiple Excel files...
1
by: nemocccc | last post by:
hello, everyone, I want to develop a software for my android phone for daily needs, any suggestions?
1
by: Sonnysonu | last post by:
This is the data of csv file 1 2 3 1 2 3 1 2 3 1 2 3 2 3 2 3 3 the lengths should be different i have to store the data by column-wise with in the specific length. suppose the i have to...
0
by: Hystou | last post by:
There are some requirements for setting up RAID: 1. The motherboard and BIOS support RAID configuration. 2. The motherboard has 2 or more available SATA protocol SSD/HDD slots (including MSATA, M.2...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.