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.

4 thoughts on “More C++: The ‘using’ Statement”

  1. The reason for all this is because C++ resolves overloads by name first. It searches for an ns::strlen, and, finding one, stops searching.

    By pulling the symbols from another scope, you copy those other strlens into ns::, and the desired overloading magic happens. (this means that you can also say ns::strlen(const char*) )

  2. This is the first time I understood your c++’ish entry. Or is it the second time o_O Anyway, hey now I’m waiting for a “pointers to methods” entry :) Oh and I got a little skilled with moonbase. Cool game, btw. Fear me~

Leave a Reply

Your email address will not be published. Required fields are marked *