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

How to make code accepting differet types work?

P: n/a
This is something I've been thinking about creating, and am trying to get
the pieces together.

I want to be able to assign values in a method accepting different types.
I.E.

MyInstance.MyMethod("IntField") = 1;
MyInstance.MyMethod("FloatField") = 2.34f;
MyInstance.MyMethod("StringField") = std::string("Hello");

Is this possible?

I know I could do it using function overloading by passing the parms, I.E.

MyInstance.MyMethod("IntField", 1);
MyInstance.MyMethod("FloatField", 2.34f);
MyInstance.MyMethod("StringField", std::string("Hello");

I'm thinking to use the assignment I would need to return a LHV, a reference
to what was being assigned. I think I just answered my own question.
Whatever I am returning would need to have operator=() overloaded for each
type.

Is this the way to go?
Jul 12 '06 #1
Share this Question
Share on Google+
9 Replies


P: n/a
Jim Langston wrote:
This is something I've been thinking about creating, and am trying to get
the pieces together.

I want to be able to assign values in a method accepting different types.
I.E.

MyInstance.MyMethod("IntField") = 1;
MyInstance.MyMethod("FloatField") = 2.34f;
MyInstance.MyMethod("StringField") = std::string("Hello");

Is this possible?

I know I could do it using function overloading by passing the parms, I.E.

MyInstance.MyMethod("IntField", 1);
MyInstance.MyMethod("FloatField", 2.34f);
MyInstance.MyMethod("StringField", std::string("Hello");

I'm thinking to use the assignment I would need to return a LHV, a reference
to what was being assigned. I think I just answered my own question.
Whatever I am returning would need to have operator=() overloaded for each
type.

Is this the way to go?

Why do the functions need to have the same name? A far more
conventional approach would be, e.g.,

MyInstance.IntField() = 1;
MyInstance.FloatField() = 2.34;
etc.

with corresponding fcn declarations:
int& IntField();
float& FloatField();
etc.

Style-conscious folk would probably go with the even more conventional
approach of setter functions:

void setIntField(int i);
void setFloatField(float f);

Jul 12 '06 #2

P: n/a
"Mark P" <us****@fall2005REMOVE.fastmailCAPS.fmwrote in message
news:%i*********************@newssvr13.news.prodig y.com...
Jim Langston wrote:
>This is something I've been thinking about creating, and am trying to get
the pieces together.

I want to be able to assign values in a method accepting different types.
I.E.

MyInstance.MyMethod("IntField") = 1;
MyInstance.MyMethod("FloatField") = 2.34f;
MyInstance.MyMethod("StringField") = std::string("Hello");

Is this possible?

I know I could do it using function overloading by passing the parms,
I.E.

MyInstance.MyMethod("IntField", 1);
MyInstance.MyMethod("FloatField", 2.34f);
MyInstance.MyMethod("StringField", std::string("Hello");

I'm thinking to use the assignment I would need to return a LHV, a
reference to what was being assigned. I think I just answered my own
question. Whatever I am returning would need to have operator=()
overloaded for each type.

Is this the way to go?

Why do the functions need to have the same name? A far more conventional
approach would be, e.g.,

MyInstance.IntField() = 1;
MyInstance.FloatField() = 2.34;
etc.

with corresponding fcn declarations:
int& IntField();
float& FloatField();
etc.

Style-conscious folk would probably go with the even more conventional
approach of setter functions:

void setIntField(int i);
void setFloatField(float f);
Yes, normally it would, but I plan on using this to assign values to a SQL
table where the string value will be a key into the field name. Keeping the
method names the same would simplify the interface for the end user (who
will probably remain me). So I could do something like:

DynSQL PlayerTable( ServerConnInfo, "Player" );
PlayerTable.reset();
PlayerTable.SetField("Name") = Player.Name;
PlayerTable.SetField("Age") = Player.Age;
PlayerTable.SetField("Sex") = Player.Sex;
PlayerTable.SetField("Strength") = Player.Str;
std::string Result = PlayerTable.insert();

So that the user doesn't have to care what types the variables are, only
have to know their names. This makes it easier for some tables such as my
item table that has 47+ fields.
Jul 12 '06 #3

P: n/a
In article <i0***************@fe07.lga>,
"Jim Langston" <ta*******@rocketmail.comwrote:
This is something I've been thinking about creating, and am trying to get
the pieces together.

I want to be able to assign values in a method accepting different types.
I.E.

MyInstance.MyMethod("IntField") = 1;
MyInstance.MyMethod("FloatField") = 2.34f;
MyInstance.MyMethod("StringField") = std::string("Hello");

Is this possible?

I know I could do it using function overloading by passing the parms, I.E.

MyInstance.MyMethod("IntField", 1);
MyInstance.MyMethod("FloatField", 2.34f);
MyInstance.MyMethod("StringField", std::string("Hello");

I'm thinking to use the assignment I would need to return a LHV, a reference
to what was being assigned. I think I just answered my own question.
Whatever I am returning would need to have operator=() overloaded for each
type.

Is this the way to go?
There are a couple of ways to handle this.

(1) You can convert everything to a single standard type before putting
them in the MyInstance object (you mentioned in a latter post about SQL,
so converting everything to strings before putting them in would work.)
Boost's lexical_cast works well for this.

class MyClass {
public:
template < typename T >
void MyMethod( T value ) {
string s = lexical_cast<string>( value );
// do stuff with s
}
};

(2) You can use the same method that the iostream classes use. Overload
MyMethod for all of the basic types, and provide a mechanism for
allowing class developers to make custom functions.

(3) You might also be able to use Boost's "Any" type depending on the
situation.
Jul 12 '06 #4

P: n/a
Jim Langston wrote:
This is something I've been thinking about creating, and am trying to get
the pieces together.

I want to be able to assign values in a method accepting different types.
I.E.

MyInstance.MyMethod("IntField") = 1;
MyInstance.MyMethod("FloatField") = 2.34f;
MyInstance.MyMethod("StringField") = std::string("Hello");

Is this possible?
Assign to what?

Could you use a map and have something like MyInstance["IntField"] = 1?

--
Ian Collins.
Jul 12 '06 #5

P: n/a
"Ian Collins" <ia******@hotmail.comwrote in message
news:4h*************@individual.net...
Jim Langston wrote:
>This is something I've been thinking about creating, and am trying to get
the pieces together.

I want to be able to assign values in a method accepting different types.
I.E.

MyInstance.MyMethod("IntField") = 1;
MyInstance.MyMethod("FloatField") = 2.34f;
MyInstance.MyMethod("StringField") = std::string("Hello");

Is this possible?
Assign to what?

Could you use a map and have something like MyInstance["IntField"] = 1?
MyInstance will, in fact, have a map, but the values will be std::string.
If I was using method overloading it would be something like (untested
code):

void MyInstance::MyMethod( std::string key, int value )
{
std::map<std::string, std::string>::iterator it = MyMap.find(key);
if ( it != MyMap.end() )
it.second = jml::StrmConvert( value );
}

StrmConvert is a template that uses stringstream to convert between types,
in this case to a std::string.

Yes, I know I can actually use this, but I would prefer to use operator= as
it just seems more natural to me.
Jul 12 '06 #6

P: n/a
Jim Langston wrote:
"Ian Collins" <ia******@hotmail.comwrote in message
news:4h*************@individual.net...
>Jim Langston wrote:
>>This is something I've been thinking about creating, and am trying
to get the pieces together.

I want to be able to assign values in a method accepting different
types. I.E.

MyInstance.MyMethod("IntField") = 1;
MyInstance.MyMethod("FloatField") = 2.34f;
MyInstance.MyMethod("StringField") = std::string("Hello");

Is this possible?
Assign to what?

Could you use a map and have something like MyInstance["IntField"] =
1?

MyInstance will, in fact, have a map, but the values will be
std::string. If I was using method overloading it would be something
like (untested code):

void MyInstance::MyMethod( std::string key, int value )
{
std::map<std::string, std::string>::iterator it = MyMap.find(key);
if ( it != MyMap.end() )
it.second = jml::StrmConvert( value );
}

StrmConvert is a template that uses stringstream to convert between
types, in this case to a std::string.

Yes, I know I can actually use this, but I would prefer to use
operator= as it just seems more natural to me.
I didn't see the beginning of the conversation, but here is my take on
what you're asking about (as I understand it):
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~
#include <string>
#include <map>

class MyClass {
std::map<std::string,inti;
std::map<std::string,floatf;
std::map<std::string,std::stringstr;
public:
class MyProxy {
MyClass& mc;
std::string key;
public:
MyProxy(MyClass& m, std::string const& k) : mc(m), key(k) {}
void operator =(int i) { mc.i[key] = i; }
void operator =(float f) { mc.f[key] = f; }
void operator =(std::string const &s) { mc.str[key] = s; }
};

MyProxy MyMethod(std::string const& k) {
return MyProxy(*this,k);
}
};

int main() {
MyClass MyInstance;
MyInstance.MyMethod("OneInt") = 0;
MyInstance.MyMethod("TwoInt") = 42;
MyInstance.MyMethod("OneFloat") = 1.0f;
MyInstance.MyMethod("TwoFloat") = 3.14159f;
MyInstance.MyMethod("OneString") = "blah";
MyInstance.MyMethod("TwoString") = "blahblah";
}

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~

Enjoy!

V
--
Please remove capital 'A's when replying by e-mail
I do not respond to top-posted replies, please don't ask
Jul 12 '06 #7

P: n/a

Victor Bazarov wrote:
Jim Langston wrote:
"Ian Collins" <ia******@hotmail.comwrote in message
news:4h*************@individual.net...
Jim Langston wrote:
This is something I've been thinking about creating, and am trying
to get the pieces together.

I want to be able to assign values in a method accepting different
types. I.E.

MyInstance.MyMethod("IntField") = 1;
MyInstance.MyMethod("FloatField") = 2.34f;
MyInstance.MyMethod("StringField") = std::string("Hello");

Is this possible?

Assign to what?

Could you use a map and have something like MyInstance["IntField"] =
1?
MyInstance will, in fact, have a map, but the values will be
std::string. If I was using method overloading it would be something
like (untested code):

void MyInstance::MyMethod( std::string key, int value )
{
std::map<std::string, std::string>::iterator it = MyMap.find(key);
if ( it != MyMap.end() )
it.second = jml::StrmConvert( value );
}

StrmConvert is a template that uses stringstream to convert between
types, in this case to a std::string.

Yes, I know I can actually use this, but I would prefer to use
operator= as it just seems more natural to me.

I didn't see the beginning of the conversation, but here is my take on
what you're asking about (as I understand it):
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~
#include <string>
#include <map>

class MyClass {
std::map<std::string,inti;
std::map<std::string,floatf;
std::map<std::string,std::stringstr;
public:
class MyProxy {
MyClass& mc;
std::string key;
public:
MyProxy(MyClass& m, std::string const& k) : mc(m), key(k) {}
void operator =(int i) { mc.i[key] = i; }
void operator =(float f) { mc.f[key] = f; }
void operator =(std::string const &s) { mc.str[key] = s; }
};

MyProxy MyMethod(std::string const& k) {
return MyProxy(*this,k);
}
};

int main() {
MyClass MyInstance;
MyInstance.MyMethod("OneInt") = 0;
MyInstance.MyMethod("TwoInt") = 42;
MyInstance.MyMethod("OneFloat") = 1.0f;
MyInstance.MyMethod("TwoFloat") = 3.14159f;
MyInstance.MyMethod("OneString") = "blah";
MyInstance.MyMethod("TwoString") = "blahblah";
}

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~

Enjoy!
Such a class would not be extensible though. An extensible version
would use templates and an "any" type class. Any type you wanted to
support would have to be registered but you'd be able to register more
types without modifying existing code.

A possible solution is a getMap<T>() function that is overloaded for
every map you support. Or you can have a single map to an "any" type
(which avoids the problem that having multiple maps would allow you to
reuse names as long as they were different types).

Once again you use overloaded functions to determine how the data is
actually stored.

Generally I solve this problem by not using an "any" class but instead
have an "opaque" class which is simply binary data, and then overloaded
converter functions You can also make each type registered with some
enumeration to check compatibility. It does rely on anything you want
to store having conversions to and from an opaque.

Jul 12 '06 #8

P: n/a

"Jim Langston" <ta*******@rocketmail.comwrote in message
news:i0***************@fe07.lga...
This is something I've been thinking about creating, and am trying to get
the pieces together.

I want to be able to assign values in a method accepting different types.
I.E.

MyInstance.MyMethod("IntField") = 1;
MyInstance.MyMethod("FloatField") = 2.34f;
MyInstance.MyMethod("StringField") = std::string("Hello");

Is this possible?

I know I could do it using function overloading by passing the parms, I.E.

MyInstance.MyMethod("IntField", 1);
MyInstance.MyMethod("FloatField", 2.34f);
MyInstance.MyMethod("StringField", std::string("Hello");

I'm thinking to use the assignment I would need to return a LHV, a
reference to what was being assigned. I think I just answered my own
question. Whatever I am returning would need to have operator=()
overloaded for each type.

Is this the way to go?
Thank you everyone for your input. This is what I have settled on.

Comments welcome. Except for people saying I shouldn't preceed my class
names with "C".

#include <string>
#include <map>
#include <sstream>
#include <iostream>

template<typename T, typename F T StrmConvert( F from )
{
std::stringstream temp;
temp << from;
T to = T();
temp >to;
return to;
}

template<typename Fstd::string StrmConvert( F from )
{
return StrmConvert<std::string>( from );
}

typedef std::map<std::string, std::string>::iterator MIt;

class CTable
{

public:

CTable()
{
Fields_["Name"];
Fields_["Age"];
Fields_["Strength"];
Fields_["Alive"];
}

class Proxy
{
public:
Proxy(CTable& mc, std::string const& key): mc_(mc), Key_(key) {}

void operator=(int Value) { Field( Key_, StrmConvert( Value ) ); }
void operator=(unsigned int Value) { Field( Key_, StrmConvert(
Value ) ); }
void operator=(float Value) { Field( Key_, StrmConvert( Value ) ); }
void operator=(bool Value) { Field( Key_, Value ? "TRUE" :
"FALSE" ); }
void operator=(const std::string &Value) { Field( Key_, "\"" + Value
+ "\"" ); }
void operator=(const char* Value) { Field( Key_, "\"" +
std::string(Value) + "\"" ); }

private:
void Field( const std::string& Key, const std::string Value )
{
MIt it_ = mc_.Fields_.find(Key_);
if ( it_ != mc_.Fields_.end() )
(*it_).second = Value;
}

CTable& mc_;
std::string Key_;
};

Proxy operator[]( const std::string& Key )
{
return Proxy(*this, Key);
}

void OutputMap()
{
for ( MIt it = Fields_.begin(); it != Fields_.end(); ++it )
std::cout << (*it).first << ":" << (*it).second << std::endl;
}

private:
std::map<std::string, std::stringFields_;

};

class CPlayer
{
public:
CPlayer(): Name_("Serpardum"), Age_(42), Strength_(13.5f), Alive_(true)
{}
std::string Name() { return Name_; }
unsigned int Age() { return Age_; }
float Strength() { return Strength_; }
bool Alive() { return Alive_; }
private:
std::string Name_;
int Age_;
float Strength_;
bool Alive_;
};

int main()
{
CPlayer Player;
CTable PlayerTable;

PlayerTable["Name"] = Player.Name();
PlayerTable["Age"] = Player.Age();
PlayerTable["Strength"] = Player.Strength();
PlayerTable["Alive"] = Player.Alive();
PlayerTable["Bogus"] = "blah blah";

PlayerTable.OutputMap();

std::string wait;
std::cin >wait;
}
Jul 12 '06 #9

P: n/a

Jim Langston wrote:
template<typename T, typename F T StrmConvert( F from )
{
std::stringstream temp;
temp << from;
T to = T();
temp >to;
return to;
}

template<typename Fstd::string StrmConvert( F from )
{
return StrmConvert<std::string>( from );
}
This looks a bit flawed. When F is std::string won't it recurse
indefinitely? Also if the string has any whitespace in it, you'll find
it scans only to the first whitespace.

I would do this:

template < typename T, typename F >
bool StrmConvert( T& to, const F& from )
{
std::stringstream ss;
ss << from;
return ( ss >to );
}

which also returns whether the conversion worked.

I would then do partial specialisation.

(Can one specialise for the case where T and F are the same?: i.e
below)

template < typename T bool StrmConvert<T, T >( T & to, const F& from
)
{
to = from;
return true;
}

template < typename T bool StrmConvert< T, std::string >
template < typename T bool StrmConvert< std::string T >

then in case it doesn't know which one to pick:

template < bool StrmConvert< std::string, std::string >

(fill them in).

Jul 17 '06 #10

This discussion thread is closed

Replies have been disabled for this discussion.