Why DOES this compile?

M

Mark

I'd like to make a class that can be implicitly cast to doubles, or
strings, or whatever (which I don't think is possible in C++).
Anyways, I came up with the following code:

struct var {
var() : dbl(0) {}
union {
double dbl;
char str[32];
};
};

double var(const var &v) {
return v.dbl;
}

Which, interestingly enough compiles without any errors. The idea
would be that I could then pass a var object to any function that
accepts doubles, like tan() for example, without having to pass in
var.dbl or anything (it would just know which variable to use via the
function provided).

However, this code seems to be completely unusable. It doesn't seem
to be possible to declare a var object, and since I can't create a var
object, I can't pass a var object to the function other... why would C+
+ even allow me write this? Shouldn't the var function and var struct
conflict?
 
K

kasthurirangan.balaji

I'd like to make a class that can be implicitly cast to doubles, or
strings, or whatever (which I don't think is possible in C++).
Anyways, I came up with the following code:

struct var {
        var() : dbl(0) {}
        union {
                double dbl;
                char str[32];
        };

};

double var(const var &v) {
        return v.dbl;

}

Which, interestingly enough compiles without any errors.  The idea
would be that I could then pass a var object to any function that
accepts doubles, like tan() for example, without having to pass in
var.dbl or anything (it would just know which variable to use via the
function provided).

However, this code seems to be completely unusable.  It doesn't seem
to be possible to declare a var object, and since I can't create a var
object, I can't pass a var object to the function other... why would C+
+ even allow me write this? Shouldn't the var function and var struct
conflict?

Conflict comes only when you use them. Remember, C++ policy is "pay
for use". Also, having lots of converters isn't a good design too.

Thanks,
Balaji.
 
T

Triple-DES

I'd like to make a class that can be implicitly cast to doubles, or
strings, or whatever (which I don't think is possible in C++).

It is possible. Consider:

struct Var
{
template<typename T>
operator T() { return T(); }
};

int main()
{
Var v;
std::string str = v; // need #include <string>
double d = v;
bool b = v;
}
 
P

Puppet_Sock

It doesn't seem
to be possible to declare a var object, and since I can't create a var
object, I can't pass a var object to the function other...

It depends what you mean by "var object."

For example: If you want to toss it the text rep of
a real number, say "1.3948E19" or some such, and have
it return the IEEE rep of a double, there needs to be
some behind-the-scenes work. Somewhere you need to
do the conversion.

On some platforms, for example VBA (VB for apps), a
var object borrows some of this from the app. If you
toss an Excel var object a string, and ask it for a
double, the var object gets Excel to do the work.
And it uses all the conversion rules that Excel uses,
formatting, over flows, round-off, notification, etc.

In C++, you need to do the work yourself. Or use a
library that does the work. And you need to decide
what to do about all those conversion issues, just
as Excel (or whatever) would have.

Another example: You used a union. Doing that won't
get you a conversion. If you put in text "1.523E19"
and then pull the double out through the union, you
won't get a double with the nearest equivalent to
that text. You will get some wonky thing due to
treating the text as though the bit patterns filled
up the double. (Modified by possible issues of the
text and the double not using the same amount of mem.)

In other words: If you want a var type, you will have
to write a var type. You will have to explicitly
write out how to do each conversion you want it to.
Text <-> double, text <-> integer, etc.
Socks
 
A

Andrey Tarasevich

Mark said:
I'd like to make a class that can be implicitly cast to doubles, or
strings, or whatever (which I don't think is possible in C++).
Anyways, I came up with the following code:

struct var {
var() : dbl(0) {}
union {
double dbl;
char str[32];
};
};

double var(const var &v) {
return v.dbl;
}

It is hard to make sense of this code. I don't see any connection from
what you wanted to do to what you actually did. What makes you think
that this class should implicitly cast to double?
Which, interestingly enough compiles without any errors.

Hmm... Why shouldn't it?
The idea
would be that I could then pass a var object to any function that
accepts doubles, like tan() for example, without having to pass in
var.dbl or anything (it would just know which variable to use via the
function provided).

And trying to implement that, how did you arrive at the above code?
However, this code seems to be completely unusable.

Well, duh...
It doesn't seem to be possible to declare a var object,

You hid your 'var' class name with 'var' function name. That's why you
can't declare a 'var' object by using a simple 'var' as a type. A simple
'var' is no longer a type.

Yet, it is still perfectly possible to declare a 'var' object. Just use
so called elaborated type specifier 'struct var' instead of simple 'var'

struct var v; // here's your object
and since I can't create a var
object, I can't pass a var object to the function other...

See above.
why would C+
+ even allow me write this? Shouldn't the var function and var struct
conflict?

They do "conflict" in a sense, but this conflict in C++ results in name
hiding, not in diagnostic message. And C++ provides you with means to
work around the hiding. So, it is up to you whether to create a name
"conflict" or not. And if you decided to create one, it is up to you to
work around it whenever necessary.
 
M

Mark

It depends what you mean by "var object."

For example: If you want to toss it the text rep of
a real number, say "1.3948E19" or some such, and have
it return the IEEE rep of a double, there needs to be
some behind-the-scenes work. Somewhere you need to
do the conversion.

On some platforms, for example VBA (VB for apps), a
var object borrows some of this from the app. If you
toss an Excel var object a string, and ask it for a
double, the var object gets Excel to do the work.
And it uses all the conversion rules that Excel uses,
formatting, over flows, round-off, notification, etc.

In C++, you need to do the work yourself. Or use a
library that does the work. And you need to decide
what to do about all those conversion issues, just
as Excel (or whatever) would have.

Another example: You used a union. Doing that won't
get you a conversion. If you put in text "1.523E19"
and then pull the double out through the union, you
won't get a double with the nearest equivalent to
that text. You will get some wonky thing due to
treating the text as though the bit patterns filled
up the double. (Modified by possible issues of the
text and the double not using the same amount of mem.)

In other words: If you want a var type, you will have
to write a var type. You will have to explicitly
write out how to do each conversion you want it to.
Text <-> double, text <-> integer, etc.
Socks

Thanks for the info. I was already aware that it would spit out
garbage if I give it a double and tell it to print a string. The idea
was that I could have one data type for everything. But once I assign
it a double, it should be treated as a double, if I then later I
assign it a string, it should be treated as a string from then on.
I'll probably need a flag keeps track of what it is... but it was just
an idea I was playing with. However, you did give me a good idea! I
*could* turn the double into a string with a simple sprintf.
 
M

Mark

Mark said:
I'd like to make a class that can be implicitly cast to doubles, or
strings, or whatever (which I don't think is possible in C++).
Anyways, I came up with the following code:
struct var {
var() : dbl(0) {}
union {
double dbl;
char str[32];
};
};
double var(const var &v) {
return v.dbl;
}

It is hard to make sense of this code. I don't see any connection from
what you wanted to do to what you actually did. What makes you think
that this class should implicitly cast to double?
Which, interestingly enough compiles without any errors.

Hmm... Why shouldn't it?
The idea
would be that I could then pass a var object to any function that
accepts doubles, like tan() for example, without having to pass in
var.dbl or anything (it would just know which variable to use via the
function provided).

And trying to implement that, how did you arrive at the above code?
However, this code seems to be completely unusable.

Well, duh...
It doesn't seem to be possible to declare a var object,

You hid your 'var' class name with 'var' function name. That's why you
can't declare a 'var' object by using a simple 'var' as a type. A simple
'var' is no longer a type.

Yet, it is still perfectly possible to declare a 'var' object. Just use
so called elaborated type specifier 'struct var' instead of simple 'var'

struct var v; // here's your object
and since I can't create a var
object, I can't pass a var object to the function other...

See above.
why would C+
+ even allow me write this? Shouldn't the var function and var struct
conflict?

They do "conflict" in a sense, but this conflict in C++ results in name
hiding, not in diagnostic message. And C++ provides you with means to
work around the hiding. So, it is up to you whether to create a name
"conflict" or not. And if you decided to create one, it is up to you to
work around it whenever necessary.

I'd never heard of this "elaborate type specifier". Seems I still
have a lot to learn about C++. I didn't think it would compile
because I thought there should have been a conflict, but clearly, I
was wrong.

I didn't actually expect the code I wrote to work or produce anything
meaningful, I was just experimenting, trying to figure out if it was
possible to create an implicit cast. I figured that natural syntax
would be

struct Var {
double Var() {
return dbl;
}
}

but... that wasn't right either, so I made something up. (Google
didn't turn up anything useful on implicit casts).
 
M

Mark

It is possible. Consider:

struct Var
{
template<typename T>
operator T() { return T(); }

};

int main()
{
Var v;
std::string str = v; // need #include <string>
double d = v;
bool b = v;

}

I didn't know you could use types as operators! That's pretty neat!
Thank you. I'll have to play around with this...
 
M

Mark

With this...

struct Var {
Var() : dbl(0) {}
Var(double d) : dbl(d) {}
Var(char* s) {
strcpy_s(str,s);
}
union {
double dbl;
char str[32];
};
operator double() {
return dbl;
}
operator int() {
return (int)(dbl+.5);
}
operator string() {
return (string)str;
}
operator char*() {
return str;
}
};

You can do stuff like...

Var var;
var = 5;
printf("%f\n",tan(var));
var = "hello";
printf("%s\n",(char*)var);
cout << (string)var << endl;
 
M

Martin York

operator int() {
return (int)(dbl+.5);
}
operator string() {
return (string)str;
}

Time to learn about the C++ cast operators.
The C cast is (in my opinion) bad style.

operator int() {
return static_cast<int>(dbl+.5);
}

Also returning a string object when Var has been initialized with a
double is probably a bad idea as the resulting string may not be
terminated and could cause lots of nasty problems that may very likely
crash your program.

You can convert doubles to strings with boost::lexical_cast<>. But I
don't think that's exactly what you want.

operator string()
{
return boost::lexical_cast<string>(dbl);
}

Returning a double when initialized with a string will return you some
random value(which may be invalid). But again not a good idea.

P.S. I hope str is large enough to hold the string s. I don't see any
checking.
 
M

Mark

With this...

struct Var {
Var() : dbl(0) {}
Var(double d) : dbl(d) {}
Var(char* s) {
strcpy_s(str,s);
}
union {
double dbl;
char str[32];
};
operator double() {
return dbl;
}
operator int() {
return (int)(dbl+.5);
}
operator string() {
return (string)str;
}
operator char*() {
return str;
}

};

You can do stuff like...

Var var;
var = 5;
printf("%f\n",tan(var));
var = "hello";
printf("%s\n",(char*)var);
cout << (string)var << endl;

Or better yet...

struct Var {
enum { NUMBER, STRING } type;
Var() : dbl(0), type(NUMBER) {}
Var(double d) : dbl(d), type(NUMBER) {}
Var(char* s) : type(STRING) {
strcpy_s(str,s);
}
union {
double dbl;
char str[32];
};
operator double() {
if(type==NUMBER) return dbl;
float f;
sscanf_s(str,"%f",&f);
return f;
}
operator int() {
if(type==NUMBER) return (int)(dbl+.5);
int i;
sscanf_s(str,"%d",&i);
return i;
}
operator char*() {
if(type==STRING) return str;
char s[32];
sprintf_s(s,"%f",dbl);
return s;
}
char* operator+(const char* s) {
char rtn[64];
strcpy_s(rtn,64,str);
strcat_s(rtn,64,s);
return rtn;
}
};

ostream& operator<<(ostream& os, const Var& v) {
if(v.type==v.STRING) return os << v.str;
else return os << v.dbl;
}

int _tmain(int argc, _TCHAR* argv[])
{
Var var = 3.14;
cout << var << endl;
var = "hello";
cout << var << endl;
var = var + " world";
cout << var << endl;
var = "2.72";
cout << (double)var*2 << endl;

....
 
K

Kira Yamato

With this...

struct Var {
Var() : dbl(0) {}
Var(double d) : dbl(d) {}
Var(char* s) {
strcpy_s(str,s);
}
union {
double dbl;
char str[32];
};
operator double() {
return dbl;
}
operator int() {
return (int)(dbl+.5);
}
operator string() {
return (string)str;
}
operator char*() {
return str;
}
};

You can do stuff like...

Var var;
var = 5;
printf("%f\n",tan(var));
var = "hello";
printf("%s\n",(char*)var);
cout << (string)var << endl;

Don't reinvent the wheel. Use

http://www.boost.org/doc/html/variant.html
 
M

Mark

With this...
struct Var {
Var() : dbl(0) {}
Var(double d) : dbl(d) {}
Var(char* s) {
strcpy_s(str,s);
}
union {
double dbl;
char str[32];
};
operator double() {
return dbl;
}
operator int() {
return (int)(dbl+.5);
}
operator string() {
return (string)str;
}
operator char*() {
return str;
}
};
You can do stuff like...
Var var;
var = 5;
printf("%f\n",tan(var));
var = "hello";
printf("%s\n",(char*)var);
cout << (string)var << endl;

Don't reinvent the wheel. Use

http://www.boost.org/doc/html/variant.html

I'm not surprised this exists. "Var" was really just a learning
experiment, but it's good to know about this "variant" in case I
actually do need to use it. Thanks for the tip.

Mark
 

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

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,582
Members
45,065
Latest member
OrderGreenAcreCBD

Latest Threads

Top