*this
home about contact feed
projects
vagra vaBlo
categories
C++(7) Solaris(4) tntnet(3) vi(3) Linux(2) DeleGate(2) Postgres(2) proxy(2) cxxtools(1) regex(1) readline(1) dtrace(1) gcc(1) MeeGo(1) ssh(1) firefox(1)

C++s special treatment of int in conjunction with operators

integral operators and int

Consider you have a class that contains operator bool() and for example operator unsiged(). What will happen if you try to convert it to let's say short?

#include<iostream>

int main(void)
{
        class Foo
        {
            public:
                operator bool() { return 1; }
                operator unsigned() { return 2; }
        } foo;

        std::cout << "Result: " << (short) foo << std::endl;

        return 0;
}

You will get an error about an ambiguous conversion. But if you convert it to int, the game will be changed, it compiles and runs:

$ CC -o foo foo.cpp && ./foo 
Result: 1

It picks operator bool(), which might surprise in the first place, but makes perfectly sense, since it is sure, that there will be no dataloss during the conversion from bool to int. But shouldn't this also be true for short? It surely is, however the C++ standard[1] is very clear about it, only a conversion from bool to int is allowed due integral promotion. The same is true, if you have operator short() and operator unsiged(), as long as only one of the operators result can be lossless converted to int, it will be picked. The special treatment in the standard for the type int is somewhat inconsistent, however, we have to live with it and at least on all compilers i tested, i got the same behavior. So it's safe to assume that you need only to keep int in mind if you use multiple operators with integral return values.

If you want to make sure, that an conversion to int uses operator unsiged(), just add an operator int() that casts from unsigned. This will also work in polymorphic classes so you add an operator int() to the baseclass that will call operator unsigned() of the derived class.

#include<iostream>
int main(void)
{

        class Foo
        {
            public:
                operator bool() { return 1; }
                virtual operator unsigned() { return 2; }
                operator int() { return (unsigned) *this; }
        };

        class Bar: public Foo
        {
            public:
                operator unsigned() { return 3; }
        } bar;

        std::cout << "Result: " << (int) bar << std::endl;

        return 0;
}
$ CC -o foo foo.cpp && ./foo 
Result: 3

[1] ISO/IEC 14882:1998 -- 4.5 - Integral promotions [conv.prom]

Write comment