ambiguous types: want automatic conversion

M

Markus Dehmann

I think this is a question about automatic type conversion, but I
didn't find the answer after googling for these words ...

I have a class called Value (source see below) which can hold an int
or a string:
Value i(23);
Value s("blah");

Now I want an implicit conversion that automatically returns the
correct type, even in a context like this:
std::cout << i; // works
std::cout << s; // doesn't work: "Not an int" exception thrown

I think this should be feasible because the object knows what to
return (it was constructed with the certain type, although that's only
at runtime, not compile time ...). Of course, I could have an
asString(), or an asInt() method in the class, but I want to avoid
that as it seems redundant. I also don't want to use external (non-
std) packages like boost.

Thanks for any help! The class I have so far is this:

class Value {
std::string stringValue;
int intValue;
bool isString;
bool isInt;
public:
Value(std::string s) : isString(true), isInt(false),
stringValue(s) {}
Value(int i) : isString(false), isInt(true), intValue(i) {}
operator std::string (){
if(!isString){throw std::runtime_error("Not a string");}
return stringValue;
}
operator int (){
if(!isInt){throw std::runtime_error("Not an int");}
return intValue;
}
};
 
R

Ron AF Greve

Hi,


Markus Dehmann said:
I think this is a question about automatic type conversion, but I
didn't find the answer after googling for these words ...

I have a class called Value (source see below) which can hold an int
or a string:
Value i(23);
Value s("blah");

Now I want an implicit conversion that automatically returns the
correct type, even in a context like this:
std::cout << i; // works
std::cout << s; // doesn't work: "Not an int" exception thrown

I think this should be feasible because the object knows what to
return (it was constructed with the certain type, although that's only
at runtime, not compile time ...). Of course, I could have an
asString(), or an asInt() method in the class, but I want to avoid
that as it seems redundant. I also don't want to use external (non-
std) packages like boost.

Thanks for any help! The class I have so far is this:

class Value {
std::string stringValue;
int intValue;
bool isString;
bool isInt;
public:
Value(std::string s) : isString(true), isInt(false),
stringValue(s) {}
Value(int i) : isString(false), isInt(true), intValue(i) {}
operator std::string (){
if(!isString){throw std::runtime_error("Not a string");}
return stringValue;
}
operator int (){
if(!isInt){throw std::runtime_error("Not an int");}
return intValue;
}
};

Yes that is possible. Just create a friend function like in my own variant
class
//------------------------ Header----------------------
class UVar
{
friend std::eek:stream& operator<<( std::eek:stream& Output, const UVar& Var );
};


std::eek:stream& operator<<( std::eek:stream& Output, const UVar& Var );
//-----------------Source
std::eek:stream& operator<<( std::eek:stream& Output, const UVar& Var )
{
Var.Print( Output );

return Output;
}


void UVar::print( ostream& Output ) const
{

switch( Type )
{
case eNull:
Output << "Null";
break;
case eLong:
Output << Long;
break;
case eDouble:
Output << Double;
break;
case eString:
Output << *reinterpret_cast<const std::string*>( String );
break;
case eMap:;
{
Output << "Map : ";

const map<UVar*,UVar*, UFindVar> Map1 =
*reinterpret_cast<map<UVar*,UVar*, UFindVar> const *const>( Map );

for( map<UVar*,UVar*, UFindVar>::const_iterator VarIter = Map1.begin();
VarIter != Map1.end(); ++VarIter )
{
Output << "Key(" << VarIter->first->type_name() << ") = " <<
*VarIter->first << "> Value{ " << VarIter->second->type_name() << ") = <"
<< *VarIter->second << ">";
}
}
break;
case eSRefPtr:
Output << "Object Classname = " << (
*reinterpret_cast<MSRefPtr<ISerialize>const*>( SRefPtr ) ?
(*reinterpret_cast<MSRefPtr<ISerialize>const*>( SRefPtr ) )->GetClassname()
: string( "SRefPtr is null" ) );
break;
case eWRefPtr:
Output << "Object Classname = " << (
*reinterpret_cast<MWRefPtr<ISerialize>const*>( WRefPtr ) ?
(*reinterpret_cast<MWRefPtr<ISerialize>const*>( WRefPtr ) )->GetClassname()
: string( "WRefPtr is null" ) );
break;
case eKey:
Output << "MKey " << *reinterpret_cast<MKey const *>( KeyStroke );
break;
default:
Channel << Chan1 << "Unknown type in UVar type = " << static_cast<int>(
Type ) << End;
throw CInfoException( "Unknown type" );
}
}


Regards, Ron AF Greve

http://www.InformationSuperHighway.eu
 
O

Old Wolf

std::cout << i; // works
std::cout << s; // doesn't work: "Not an int" exception thrown

class Value {
std::string stringValue;
int intValue;
bool isString;
bool isInt;
public:
Value(std::string s) : isString(true), isInt(false),
stringValue(s) {}
Value(int i) : isString(false), isInt(true), intValue(i) {}
operator std::string (){
if(!isString){throw std::runtime_error("Not a string");}
return stringValue;
}
operator int (){
if(!isInt){throw std::runtime_error("Not an int");}
return intValue;
}
};

Well, this code will work. However it is quite obfuscated.

operator<< for std::eek:stream accepts both int and std::string.
However, int is selected because it is a builtin type. If
you had another conversion , e.g. operator double(), defined
you would get an ambiguous error.

It would be better to make the logic more explicit, i.e.
define operator<<(std::eek:stream &, Value) .
 
J

Jeff F

Markus Dehmann said:
I think this is a question about automatic type conversion, but I
didn't find the answer after googling for these words ...

I have a class called Value (source see below) which can hold an int
or a string:
Value i(23);
Value s("blah");

Now I want an implicit conversion that automatically returns the
correct type, even in a context like this:
std::cout << i; // works
std::cout << s; // doesn't work: "Not an int" exception thrown

Switch to boost::variant which has an insertion operator(untested)

#include <boost/variant.hpp>
#include <string>
#include <ostream>

int main()
{
boost::variant<int,std::string> v;

v = std::string("abc");

std::cout << v << std::endl;

v = 123;

std::cout << v << std::endl;

}

Jeff Flinn
 

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

Forum statistics

Threads
473,969
Messages
2,570,161
Members
46,705
Latest member
Stefkari24

Latest Threads

Top