天天看點

Tag dispatching

Tag dispatching

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 C++ 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:

1

#include <iostream>

2

3

struct

fast_speed_tag {};

4

struct

slow_speed_tag {};

5

6

template

<

typename

T>

7

struct

traits {

// default

8

typedef

slow_speed_tag speed;

9

};

10

11

template

<>

12

struct

traits<

int

> {

// we would do the same for long etc

13

typedef

fast_speed_tag speed;

14

};

15

16

template

<

typename

T>

17

void

work_dispatch (

const

T &val,

const

slow_speed_tag&) {

18

std::cout <<

"slow"

<< std::endl;

19

}

20

21

template

<

typename

T>

22

void

work_dispatch (

const

T &val,

const

fast_speed_tag&) {

23

std::cout <<

"fast"

<< std::endl;

24

}

25

26

template

<

typename

T>

27

void

work (

const

T &val) {

28

work_dispatch(val,

typename

traits<T>::speed());

29

}

30

31

int

main () {

32

int

x;

33

float

y;

34

35

work(x);

// fast

36

work(y);

// slow

37

38

return

0;

39

}

Another thing worth mentioning is that, the tag types are empty structs that are never used. As such, the compiler will usually be able to optimize and 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.

繼續閱讀