checked_cast

This entry assumes you are familiar with the new-style C++ cast operators, static_cast<>, dynamic_cast<>, and friends. Occasionally a situation like this arises:

Base* b = new Derived;

// ...

Derived* d = static_cast<Derived*>(b);

You know b points to a Derived object and you want to get back at that. The “type-safe” thing to do is store an additional pointer that holds the original Derived object. This may be an unreasonable request: maybe you can’t afford the additional memory required, or maybe the Base* pointer is in some external library, or maybe the ownership semantics become unclear. What you really want is a way to assert in debug mode if your cast fails, but incur no overhead in release builds. Here’s where checked_cast comes in!

Base* b = new Derived;
Derived* d = checked_cast<Derived*>(b);  // Checked in debug, fast in release.

And now the implementation:

template<typename T, typename U>
bool check_type(U* u) {
    return (!u || dynamic_cast<T>(u) ? true : false);
}

template<typename T, typename U>
bool check_type(U& u) {
    try {
        dynamic_cast<T>(u);
        return true;
    }
    catch (const std::bad_cast&) {
    }
    return false;
}

template<typename T, typename U>
T checked_cast(U* u) {
    assert(check_type<T, U>(u));
    return static_cast<T>(u);
}

template<typename T, typename U>
T checked_cast(U& u) {
    assert(check_type<T, U>(u));
    return static_cast<T>(u);
}

Works like a charm! Or… not. Well, it works fine in MIPSPro and Visual Studio, at least. gcc 3.x has a bug that prevents template resolution from working in this situation. The workaround is to rename the reference versions of checked_cast to checked_cast_ref.

Credit where credit due. I came up with an independent implementation of checked_cast, and when I started running into compiler troubles, I searched online for it. Turns out there are a few others. :) This post is the first place I know of that has a complete discussion.

p.s. It really sucks to format C++ as HTML? Anyone know of a tool that can automatically do this?

More C++: The ‘using’ Statement

When using C-style APIs, take OpenGL for example, from C++, sometimes it’s nice to provide your own overloads that understand your app-specific classes. Often, I write a glVertex overload that takes Vec3f, Vec4f, Vec3d, etc. You can overload glVertexPointer in similar ways. If you’re working in your own namespace (as you should be!), you’ll quickly run into a problem… your “overload” shadows the original function, if it’s in a different namespace!

// Example:
namespace ns {
    struct MyString {
        size_t length() const {
            return 42;
        }
    };

    // using ::strlen;  // This line of code lets you use the original functions too!
    size_t strlen(const MyString& s) {
        return s.length();
    }

    void run() {
        MyString str;
        const char* cstr = "Hello!";

        size_t str_len  = strlen(str);   // works!
        size_t cstr_len = strlen(cstr);  // Uh oh, strlen() takes MyString, not const char*!
    }
}

There are two ways you can fix this. One is obvious, but annoying. Instead of calling strlen() when you want to call it on const char*, fully scope the version you want to use: ::strlen(). This works, but is a hassle. You have to change all of the places you call strlen, etc. etc. The other solution is to bring the original function you’re overloading into your namespace so that C++ sees *all* of the overloads, not just your new ones. You can do this with a ‘using’ statement as such: “using ::strlen;” Oddly enough, that one statement brings all of the strlen overloads into your namespace. Less obvious, but works better.

Perhaps you’ve run into a variant of this problem. (I know andy has.) You have two classes. One derives from the other. The base class provides a method, and perhaps an overload for it. You want to add your own overload to the derived class, but still be able to call the base class’s overloads. Uh oh!

struct Object {
    void imbue(int value) {
        cout << "imbue(int): " << value << endl;
    }
};

struct CustomObject : Object {
    //using Object::imbue;
    void imbue(const char* value) {
        cout << "imbue(string): " << value << endl;
        imbue(atoi(value));  // Ack!  imbue does not take an int!
    }
};

void run() {
    CustomObject c;
    c.imbue(10);  // Ack!  imbue does not take an int!
    c.imbue("42");
}

Notice that the 'using' statement comes to the rescue again! You can bring the method from the base class down to the derived one's scope, putting it on equal footing in overload resolution. This sure beats explicitly specifying the base class's scope when calling the original methods!:

void run() {
    CustomObject c;
    c.Object::imbue(10);  // Blech!
    c.imbue("42");
}

from the education-is-about-teaching-too dept.

Templates and Compilers Make My Head Spin

I found a bug in Visual C++ 7.1 today. I wanted to write my own C++ allocator that I could use in a std::set. Since std::allocator does 90% of what I need, I derived my own allocator from it and reimplemented two (actually, two + rebind) things:

template<typename T>
struct Win32Allocator : public std::allocator<T> {
    template<typename U>
    struct rebind {
        typedef Win32Allocator<U> other;
    };

    pointer allocate(size_type count, void* /*hint*/ = 0) {
        // ...
    }

    void deallocate(pointer p, size_type /*size*/) {
        // ...
    }
};

Looks good. Works fine for vector, list, map. Also works fine for std::set in gcc, but not in VC++ 7.1, the compiler in which I need this to work. VC++ gives the following error:

C:\Program Files\Microsoft Visual Studio .NET 2003\Vc7\include\set(24) : error C2248: 'Win32Allocator<T>::rebind<U>::other' : cannot access inaccessible typedef
declared in class 'Win32Allocator<T>'

Wut! Everything is public! How can the typedef be inaccessible? Oddly enough, if I make the typedef private, the format of the error message changes… Something fishy is going on. Some googling gives the following conclusions:

  • Only one other person has run into this and documented the problem online.
  • Nobody has an answer.
  • This technique works fine in VC++ 6 and 7.0.
  • The annoying and semi-ugly workaround of implementing your own allocator without deriving from std::allocator works fine.

I decided to not derive from std::allocator, but bleh. That plus unexpected Boost.Python behavior has made this a headache-inducing day, and I’ve only been up for six hours.