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

Are conversion operators "illegal" in C++/CLI?

P: n/a
I have some problems using conversion operators in C++/CLI. In my
project I have two ref class:es Signal and SignalMask and I have an
conversion function in Signal to convert Signal:s to SignalMask:s. The
reason is I have a free function called WaitSignal that accepts av
SignalMask where Signals parameters are supposed to implicitly be
converted to SignalMask:s. I'm using the SignalMask class because I
want to be able to supply a logic expression of which signals I want to
listen to at the same time:

WaitSignal(s1 || s2 || s3); // wait for any of the three signals

But to make the function WaitSignal accept a single Signal argument I'm
relying on the conversion operator in the Signal class to convert a
Signal argument to a SignalMask. As in normal C++ this requires a const
reference to work since it's not allowed to call a function with a
non-const temporary object.

That's fine. But the problem is that in C++/CLI you are not allowed to
use a const object in *any* way since you cannot specify which
operations on a class is const and which are not.

So I'm required to supply a const object reference to call the
conversion operator but then I cannot use the object! I'm I missing
something or is this a known problem in C++/CLI?

Note that I'm using the ref classes with stack semantic to
deteministically destruct the objects.

A simple example:
=================

ref class SignalMask;

ref class Signal {
public:
operator SignalMask();
};

ref class SignalMask {
public:
SignalMask(SignalMask% other);

void DoAnything() { }
};

void WaitSignal(const SignalMask% mask)
{
// *any* use of object mask is forbidden
// - even const operations (which you can't specify)
mask.DoAnything();
}

int main()
{
Signal s1;
WaitSignal(s1);

return 0;
}

If I remove the const qualifier in WaitSignal(const SignalMask% mask)
the conversion operator is not invoked and if I keep const I cannot use
the object supplied. Catch 22!

Thanks in advance.

Best Regards,
Phl

Dec 29 '05 #1
Share this Question
Share on Google+
4 Replies


P: n/a
"Phl Melin" <pa********@zenterio.com> wrote

I have some problems using conversion operators in C++/CLI. In my
project I have two ref class:es Signal and SignalMask and I have an
conversion function in Signal to convert Signal:s to SignalMask:s. The
reason is I have a free function called WaitSignal that accepts av
SignalMask where Signals parameters are supposed to implicitly be
converted to SignalMask:s. I'm using the SignalMask class because I
want to be able to supply a logic expression of which signals I want to
listen to at the same time:

WaitSignal(s1 || s2 || s3); // wait for any of the three signals

<hg>
There are probably better ways to achieve what you want, but that
depends on the way these classes are related.
</hg>

But to make the function WaitSignal accept a single Signal argument I'm
relying on the conversion operator in the Signal class to convert a
Signal argument to a SignalMask. As in normal C++ this requires a const
reference to work since it's not allowed to call a function with a
non-const temporary object.

<hg>
I don't quite understand. If both Signal and SignalMask are ref classes
you could return provide a conversion to SignalMask^.
</hg>

That's fine. But the problem is that in C++/CLI you are not allowed to
use a const object in *any* way since you cannot specify which
operations on a class is const and which are not.

<hg>
You can still use cv qualifiers in signatures. Just the member function
qualifiers are not accepted. I believe the reasoning behind it was,
that cv qualified member functions are of little use.
</hg>

So I'm required to supply a const object reference to call the
conversion operator but then I cannot use the object! I'm I missing
something or is this a known problem in C++/CLI?

<hg>
The conversion operator does not need to be const. You would
really need to be able to add a const qualifier to DoAnything.
</hg>

Note that I'm using the ref classes with stack semantic to
deteministically destruct the objects.

<hg>
Ah, I see. In that case you're out of luck, I'm afraid :-(
Standard C++ idioms don't work too great in the managed world.
And as AFAICT it was not considered an important design goal
for the C++/CLI language design.

Anyway, you can always cast constness away with a const_cast.

const_cast<SignalMask%>(mask).DoAnything();

</hg>

-hg
Dec 29 '05 #2

P: n/a
> I'm using the SignalMask class because I want to be able to
supply a logic expression of which signals I want to listen to
at the same time:

WaitSignal(s1 || s2 || s3); // wait for any of the three signals

<hg>
There are probably better ways to achieve what you want, but that
depends on the way these classes are related.
</hg>
Any ideas? I want to be able to extend the idea in the future to allow
any type of logic expression based on which signals have arrived (been
raised) like:

// wait for both signal s1 and s2 to be raised or a timeout signal
WaitSignal(s1 && s2 || timeoutSignal);
<hg>
You can still use cv qualifiers in signatures. Just the member function
qualifiers are not accepted. I believe the reasoning behind it was,
that cv qualified member functions are of little use.
</hg>
Yes, I can use a const qualifier in the function signature (as I did)
but then it's not possible to use the parameter, so there is little
point doing it.

I thought they didn't allow cv qualifiers because the CLR and the other
..net languages doesn't support const at all. But they are *required* if
you want to combine stack semantic with temporary objects, like when
you invoke an implicit conversion operator as I do in my example. To
me, it looks like a clash between ISO C++ and C++/CLR semantics.
Note that I'm using the ref classes with stack semantic to
deterministically destruct the objects.

<hg>
Ah, I see. In that case you're out of luck, I'm afraid :-(
Standard C++ idioms don't work too great in the managed world.
And as AFAICT it was not considered an important design goal
for the C++/CLI language design.
I probably got carried away by the praise Microsoft and Herb Sutter
gives to themselves for allowing the classic RAII idiom in C++/CLI. It
sounded like you could use the ISO C++ stack semantic for all ref
classes in C++/CLI. But they list a few classes in the help files that
doesn't support stack semantic, like System:String.

The problem IMHO is that when you almost implement a new feature it
creates uncertainty about when to use is at all if it just works in
*some* cases and the code gets confusing when you are combining
different techniques for the same problem in the same function or
module (having some stack objects and some gc objects in the same
function - it hard to understand the motive by e.g. a maintenance
programmer looking through the code later on).

But still, I totally agree on the value of having deterministic
destructors so I would like to use it as much as possible. I just have
to learn when it works and when it doesn't work.
Anyway, you can always cast constness away with a const_cast.

const_cast<SignalMask%>(mask).DoAnything();


Hadn't thought about that. But IMHO this is really ugly and is only a
last resort (mostly a work-around when mutable haven't been used). It
shouldn't be done in a standard solution like just getting the
conversion operator work. I would prefer another solution, if possible.

One way to solve it, I presume, would be to make the SignalMask class
non-managed (a normal class). Or to supply an extra overload of the
WaitSignal() function that takes a single Signal% parameter and creates
a non-temporary SignalMask object and calls the "real" WaitSignal()
function.

Dec 29 '05 #3

P: n/a
"Phl Melin" <pa********@zenterio.com> wrote
There are probably better ways to achieve what you want, but that
depends on the way these classes are related.
</hg>


Any ideas? I want to be able to extend the idea in the future to allow
any type of logic expression based on which signals have arrived (been
raised) like:

// wait for both signal s1 and s2 to be raised or a timeout signal
WaitSignal(s1 && s2 || timeoutSignal);

You could use a common base (or interface) for your classes.
You may also want to use some expression template techniques
(creating class template wrappers for the above expressions
and deferring the evaluation to a later point in time)

Oc, you could also add cleanup handling to the WaitSignal
implementation or use native classes for the wrappers.
Note that I'm using the ref classes with stack semantic to
deterministically destruct the objects.

<hg>
Ah, I see. In that case you're out of luck, I'm afraid :-(
Standard C++ idioms don't work too great in the managed world.
And as AFAICT it was not considered an important design goal
for the C++/CLI language design.


I probably got carried away by the praise Microsoft and Herb Sutter
gives to themselves for allowing the classic RAII idiom in C++/CLI. It
sounded like you could use the ISO C++ stack semantic for all ref
classes in C++/CLI. But they list a few classes in the help files that
doesn't support stack semantic, like System:String.

There are indeed things in the language design which make me
shake my head in disbelief. That said, we can still hope that
C++/CLI will evolve faster than ISO C++ and that some of the
issues will be fixed. But I guess, that would require someone of the
Softies to grasp it :-O

-hg
Dec 29 '05 #4

P: n/a
Phl Melin wrote:
If I remove the const qualifier in WaitSignal(const SignalMask% mask)
the conversion operator is not invoked and if I keep const I cannot use
the object supplied. Catch 22!


That's an interesting observation. You're out of luck here, because the
..NET framework doesn't support the concept of const member functions.
You really shouldn't use the const keyword anywhere, you'll just get
into trouble with that, as you won't be able to call any of the member
functions of a const object (and the const_cast hack is not worth it, in
my opinion, unless you absolutely have no other choice).

In ISO C++ the conversion operator works when you pass by value or by
const reference. In C++/CLI you can't pass a ref class by value and
can't pass it by const reference either (in a meaningful way), so you're
out of luck. From your example it seems to me that conversion operators
make little sence with ref classes, as there's not a signle practical
case in which they would be called automatically. As Holger said, not
all ISO C++ idioms work well in .NET.

Even in ISO C++, I would question the conversion operator in this case.
It may be dangerous, as you could accidentally convert a Signal to
SignalMask, without even a warning. I tend not to define conversion
operators unless the two types are completely interchangeable without
significant loss of data. But that's a different topic.

Tom
Jan 2 '06 #5

This discussion thread is closed

Replies have been disabled for this discussion.