cplusplus.co.il

Tag dispatching

Posted on: 03/01/2010

Tag dispatching is a technique for compile time dispatching between a few overloaded functions by using the properties of a type. This technique usually involves some kind of type traits.

Suppose you needed to carry out some task, in the form of a work() function. What is interesting is that it is possible to write two different such functions: one that is able to work pretty fast (by using bitwise operations for example), and a normal – slow – one (which uses regular arithmetic). The fast approach will only work with some types (say, integral types like int, long, etc), while the regular implementation is fine for just about any type. The thing is, overloading these two functions for all the types in the system is pretty much impossible. And even if it was, maintaining such a thing is surely not going to be any fun. So we’re looking for an elegant solution.

Obviously, tag dispatching can be the answer. Otherwise why would I  be telling this long story?

Most software systems already contain some form of a traits mechanism. We would like to add another typedef to these traits – one that will tell us exactly whether we can use the fast implementation, or not. Once the traits have been set up, all we need to do is overload the two distinct work_dispatch() functions, and have a main work() function which will actually carry out the traits-based dispatch. Here is how the implementation could look like:

#include <iostream>

struct fast_speed_tag {};
struct slow_speed_tag {};

template <typename T>
struct traits { // default
    typedef slow_speed_tag speed;
};

template <>
struct traits<int> { // we would do the same for long etc
    typedef fast_speed_tag speed;
};

template <typename T>
void work_dispatch (const T &val, const slow_speed_tag&) {
    std::cout << "slow" << std::endl;
}

template <typename T>
void work_dispatch (const T &val, const fast_speed_tag&) {
    std::cout << "fast" << std::endl;
}

template <typename T>
void work (const T &val) {
    work_dispatch(val, typename traits<T>::speed());
}

int main () {
    int x;
    float y;

    work(x); // fast
    work(y); // slow

    return 0;
}

Another thing worth mentioning is that, the tag types are empty structs that are never used. As such, the optimizer will usually be able to make them totally disappear from the compiled code – which makes this technique even more appealing.

One of the best examples of the Tag dispatch technique is the implementation of std::advance() within STL iterators. You can read more about it here.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: