473,320 Members | 1,939 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,320 software developers and data experts.

template conversion operator clarification needed

Hello,

I have come back to C++ after a couple of years with Java so I am quite
rusty and this question may seem poor:

My platform is Windows XP with MSVC 7.1.

I have a class with a templatized conversion operator defined as
follows:

----------------------------------------------------------
template<class T>
class IBitImpl : public virtual IBit<T>
{
std::numeric_limits<T> m_limits;
T m_bit;
// other fns/ctor's etc

template<class C> operator C() const
throw(InvalidCastException)
{
if(std::numeric_limits<C>::digits < m_limits.digits)
{
throw InvalidCastException(L"Invalid argument -
Destination type C cannot accomodate source type T. ");
}
return (C) m_bit;
}
};
----------------------------------------------------------

So, I up and write a simple test:

----------------------------------------------------------
int x = 121234234;
IBitImpl<int> lowbit2(2);
bool isset = (1 == (x & lowbit2));
std::cout<<"Is bit "<<lowbit2.Bit()<<" in "<<x<<" set?
"<<std::boolalpha<<isset<<std::endl;
----------------------------------------------------------

I get an error indicating that there is an ambiguity because in (x &
lowbit2) the conversion can be any one of (long, bool, unsigned long,
etc).

I thought that the compiler looks at x and upcasts lowbit2 to the
appropriate type (in this case int). This doesn't seem to be the case
here.

I figured the whole problem ws because of the conversion operator
defined above. Consequently, I changed the expression to make the case
explicit as follows:

---------------------------------------------------------
bool isset = (1 == (x & (int) lowbit2));
---------------------------------------------------------

which needless to say, worked fine. However, I don't understand why the
correct cast isn't automatically applied. I am missing something here
and would appreciate it if someone would point me in the right
direction.

thanks,

-vijai.

Aug 6 '05 #1
5 3002
My stupidity. The code snippet for the expression should be

bool isset = ( (x & (int) lowbit2));

However, that doesn't detract from my original question.

-vijai.

Aug 7 '05 #2
* Vijai Kalyan:

I have come back to C++ after a couple of years with Java
Noted.

so I am quite
rusty and this question may seem poor:

My platform is Windows XP with MSVC 7.1.
Irrelevant.

I have a class with a templatized conversion operator defined as
follows:

----------------------------------------------------------
template<class T>
class IBitImpl : public virtual IBit<T>
Naming: "Bit" would be a good name for this class.
Performance/design: difficult to see any advantage in having IBit<T>.
{
std::numeric_limits<T> m_limits;
Should be a 'typedef' (if anything), not a data member.

T m_bit;
Naming: is this the bit number, let's call it n, or is it the bit
value 1<<n?

Only for the latter case does it make sense to use type T.

In the test program it seems there is a member function that computes n from
m_bit, which is a bit awkward, opposite of the simplest & most efficient.

// other fns/ctor's etc

template<class C> operator C() const
throw(InvalidCastException)
Javaism : avoid throw specifications in C++, except 'throw()'.
Design : don't be afraid to use 'assert'.
Types : if possible use standard exception classes or classes derived from
them, e.g. here, std::bad_cast (but: rather 'assert' instead).
{
if(std::numeric_limits<C>::digits < m_limits.digits)
See above regarding 'm_limits'.

{
throw InvalidCastException(L"Invalid argument -
Destination type C cannot accomodate source type T. ");
See above regarding exception types and use of 'assert'.

}
return (C) m_bit;
Javaism (and also C-ism): don't use C-style casts. Use e.g. static_cast.

See above regarding naming and resulting confusion about what 'm_bit' is.
}
};
----------------------------------------------------------

So, I up and write a simple test:

----------------------------------------------------------
int x = 121234234;
IBitImpl<int> lowbit2(2);
bool isset = (1 == (x & lowbit2));
std::cout<<"Is bit "<<lowbit2.Bit()<<" in "<<x<<" set?
"<<std::boolalpha<<isset<<std::endl;
----------------------------------------------------------

I get an error indicating that there is an ambiguity because in (x &
lowbit2) the conversion can be any one of (long, bool, unsigned long,
etc).
Yes. Built-in operators do not constrain the types of their arguments,
except to the set of types the operator in question is defined for.
However, if you define your own '&' operator you can do that, e.g.

template< typename T, typename U >
T operator&( T a, Bit<U> const& b ){ return a & static_cast<T>( b ); }

template< typename T, typename U >
U operator&( Bit<T> const& a, U b ){ return static_cast<U>( a ) & b; }

I thought that the compiler looks at x and upcasts lowbit2 to the
'upcast' is something else entirely; here you're talking about a conversion,
in no particular direction.

appropriate type (in this case int). This doesn't seem to be the case
here.

I figured the whole problem ws because of the conversion operator
defined above. Consequently, I changed the expression to make the case
explicit as follows:

---------------------------------------------------------
bool isset = (1 == (x & (int) lowbit2));
---------------------------------------------------------

which needless to say, worked fine. However, I don't understand why the
correct cast isn't automatically applied.
There is no correct conversion because there is no constraint whatsoever
(except to the set of types that the built-in '&' is defined for).

I am missing something here
and would appreciate it if someone would point me in the right
direction.


See above.

--
A: Because it messes up the order in which people normally read text.
Q: Why is it such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?
Aug 7 '05 #3
> > ----------------------------------------------------------
template<class T>
class IBitImpl : public virtual IBit<T>
Naming: "Bit" would be a good name for this class.
Performance/design: difficult to see any advantage in having IBit<T>.


Well, IBit is really the interface that defines the requirements for
IBitImpl.

template<class T>
class IBit
{
public:
template<class C> IBit<T>& operator=(C);
template<class C> IBit<T>& operator=(const IBit<C>&);
template<class C> operator C() const;

virtual inline T Bit() const = 0;
virtual inline T Mask() const = 0;
};
{
std::numeric_limits<T> m_limits;
Your are right. A member is not called for.
Should be a 'typedef' (if anything), not a data member.

T m_bit;
Naming: is this the bit number, let's call it n, or is it the bit
value 1<<n?


m_bit is the bit number. There is a data member m_mask that stores the
mask.
Only for the latter case does it make sense to use type T.
Here, I don't know. I presume an 'int' or 'short' can equally hold all
possible bit numbers.
In the test program it seems there is a member function that computes n from
m_bit, which is a bit awkward, opposite of the simplest & most efficient.
No. The mask is computed when the object is created and stored in
m_mask of type T.
// other fns/ctor's etc

template<class C> operator C() const
throw(InvalidCastException)


Javaism : avoid throw specifications in C++, except 'throw()'.
Design : don't be afraid to use 'assert'.
Types : if possible use standard exception classes or classes derived from
them, e.g. here, std::bad_cast (but: rather 'assert' instead).


True. I should have used bad_cast. On the other hand, most of the
standard exception classes don't seem to have a wide-string variant of
their constructors. I would rather not mix the two and prefer to use
the wide-string variant where possible. Of course, that is irrelevant
strictly speaking. I can derive form bad_cast and provide a
wide-string constructor.
{
if(std::numeric_limits<C>::digits < m_limits.digits)


See above regarding 'm_limits'.

{
throw InvalidCastException(L"Invalid argument -
Destination type C cannot accomodate source type T. ");


See above regarding exception types and use of 'assert'.

}
return (C) m_bit;


Javaism (and also C-ism): don't use C-style casts. Use e.g. static_cast.


My mistake.
See above regarding naming and resulting confusion about what 'm_bit' is.


As I said, m_bit is the bit number. m_mask is the actual mask. So,

m_mask = (1 << m_bit);
}
};
----------------------------------------------------------

So, I up and write a simple test:

----------------------------------------------------------
int x = 121234234;
IBitImpl<int> lowbit2(2);
bool isset = (1 == (x & lowbit2));
std::cout<<"Is bit "<<lowbit2.Bit()<<" in "<<x<<" set?
"<<std::boolalpha<<isset<<std::endl;
----------------------------------------------------------

I get an error indicating that there is an ambiguity because in (x &
lowbit2) the conversion can be any one of (long, bool, unsigned long,
etc).


Yes. Built-in operators do not constrain the types of their arguments,
except to the set of types the operator in question is defined for.
However, if you define your own '&' operator you can do that, e.g.

template< typename T, typename U >
T operator&( T a, Bit<U> const& b ){ return a & static_cast<T>( b ); }

template< typename T, typename U >
U operator&( Bit<T> const& a, U b ){ return static_cast<U>( a ) & b; }

I thought that the compiler looks at x and upcasts lowbit2 to the


'upcast' is something else entirely; here you're talking about a conversion,
in no particular direction.


Ah, I see. Ok. Well, I thought about defining those operators and then
started wondering why the conversion operator wouldn't work in general.
Of course, that means I would have to define a | operator as well.
appropriate type (in this case int). This doesn't seem to be the case
here.

I figured the whole problem ws because of the conversion operator
defined above. Consequently, I changed the expression to make the case
explicit as follows:

---------------------------------------------------------
bool isset = (1 == (x & (int) lowbit2));
---------------------------------------------------------

which needless to say, worked fine. However, I don't understand why the
correct cast isn't automatically applied.


There is no correct conversion because there is no constraint whatsoever
(except to the set of types that the built-in '&' is defined for).

I am missing something here
and would appreciate it if someone would point me in the right
direction.


See above.


Great! Thanks a lot for the clarifications.

-vijai.

Aug 7 '05 #4
* Vijai Kalyan:
}
return (C) m_bit;


Javaism (and also C-ism): don't use C-style casts. Use e.g. static_cast.


My mistake.
See above regarding naming and resulting confusion about what 'm_bit' is.


As I said, m_bit is the bit number. m_mask is the actual mask. So,

m_mask = (1 << m_bit);


In that case, in the test program's

bool isset = (1 == (x & lowbit2));


the sub-expression (I've added the necessary static_cast)

x & static_cast<int>( lowbit2 )

will not give correct result, because x isn't and'ed with a mask but with a
bitnumber.

This particular bug would probably have been avoided with more descriptive
naming... ;-)

There's also another bug in that expression, namely, the comparision with 1.

To avoid silly warnings from the compiler you can

A) compare the '&' result with the mask, or
B) compare the '&' result with 0, or
C) apply the negation operator '!' twice to the '&' result.

To avoid such bugs in general, try to design classes where it requires great
effort to use them incorrectly -- e.g., take control of all relevant ops.

--
A: Because it messes up the order in which people normally read text.
Q: Why is it such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?
Aug 7 '05 #5
As a matter of fact, it is kind of funny.

The conversion operator actually returns the "mask" instead of the
"bit". So,

(x & lowbit2)

would work.

But that is not really why I replied.

Considering that in the above expression, an explicit cast is required
to use the mask writting the correct expression as:

x & (int) lowbit2

really enforces a certain amount of safety primarily because the
conversion operator applied checks to make sure that the destination
type (in this case int) can actually hold the mask. I would think that
is actually a "good side-effect" of the conversion operator although I
am not too sure.

For example, the following would most definitely throw a runtime
exception "bad_cast"

char x = 'a';
x & (char) lowbit2.

Likewise, so would the following:

IBitImpl<int> lowbiti(2);
IBitImpl<char> lowbitc = lowbiti;

This of course not being due to the conversion operator but due to the
templatized constructor:

template<typename C> IBitImpl(const IBitImpl<C>&)

which also performs the check that C can hold T.

However, the following wouldn't:

IBitImpl<char> lowbitc(2);
IBitImpl<int> lowbiti = lowbitc;

since an integer mask can certainly accomodate a char mask.

Interesting no?

-vijai.

Aug 8 '05 #6

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

Similar topics

21
by: Makhno | last post by:
Hello, Why does my cast from Vector<class Float> to Vector<float> not work? It won't compile, template<class Float> class Vector { public: Vector(Float x1,Float y1,Float...
15
by: iuweriur | last post by:
A few questions on the curiously recurring template pattern: This page: http://c2.com/cgi/wiki?CuriouslyRecurringTemplate this part: template<typename T> struct ArithmeticType { T operator...
3
by: BigMan | last post by:
Here is a piece of code: #include <memory> using namespace std; template< typename SomeType > void f(auto_ptr_ref< SomeType >) { }
3
by: Kevin Ruland | last post by:
Hi all. I have a template class with conversion operator: template< typename T > class FooWrapper { public: FooWrapper( const T& rhs ); }
3
by: CoolPint | last post by:
After upgrading to gcc 3.4.2 from gcc 3.2.3, I got compiler errors that I could not figure out. After reading other postings, I learned that my coding was not compliant to the standard in the first...
6
by: YUY0x7 | last post by:
Hi, I am having a bit of trouble with a specialization of operator<<. Here goes: class MyStream { }; template <typename T> MyStream& operator<<(MyStream& lhs, T const &)
3
by: Chris | last post by:
I am having a very strange problem involving virtual functions in template classes. First of all, here is an extremely simplified structure of the two classes I am having problems with. ...
12
by: Jim Langston | last post by:
I have a template I call StrmConvert, which uses std::stringstream to convert from any type to any other type that can be used by stringstring. This is what it looks like: template<typename T,...
3
by: Hamilton Woods | last post by:
Diehards, I developed a template matrix class back around 1992 using Borland C++ 4.5 (ancestor of C++ Builder) and haven't touched it until a few days ago. I pulled it from the freezer and...
0
by: DolphinDB | last post by:
Tired of spending countless mintues downsampling your data? Look no further! In this article, you’ll learn how to efficiently downsample 6.48 billion high-frequency records to 61 million...
1
isladogs
by: isladogs | last post by:
The next Access Europe meeting will be on Wednesday 6 Mar 2024 starting at 18:00 UK time (6PM UTC) and finishing at about 19:15 (7.15PM). In this month's session, we are pleased to welcome back...
0
by: Vimpel783 | last post by:
Hello! Guys, I found this code on the Internet, but I need to modify it a little. It works well, the problem is this: Data is sent from only one cell, in this case B5, but it is necessary that data...
0
by: jfyes | last post by:
As a hardware engineer, after seeing that CEIWEI recently released a new tool for Modbus RTU Over TCP/UDP filtering and monitoring, I actively went to its official website to take a look. It turned...
1
by: PapaRatzi | last post by:
Hello, I am teaching myself MS Access forms design and Visual Basic. I've created a table to capture a list of Top 30 singles and forms to capture new entries. The final step is a form (unbound)...
0
by: Defcon1945 | last post by:
I'm trying to learn Python using Pycharm but import shutil doesn't work
1
by: Shællîpôpï 09 | last post by:
If u are using a keypad phone, how do u turn on JavaScript, to access features like WhatsApp, Facebook, Instagram....
0
by: af34tf | last post by:
Hi Guys, I have a domain whose name is BytesLimited.com, and I want to sell it. Does anyone know about platforms that allow me to list my domain in auction for free. Thank you
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...

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.