Advantages of an empty class in C++

The following can be used to have a boost::variant which can hold an (SQL) NULL value for example.

class Null { };

typedef boost::variant<Null, std::string, int> Value;

To make it more useful things like operator== and operator<< are handy. For example:

std::ostream& operator<<(std::ostream &lhs, const Null &rhs)
{
     lhs << "*NULL*";
     return lhs;
}

int main()
{
    Variant v("hello");
    std::cout << v << std::endl;
    v = Null();
    std::cout << v << std::endl;
    ...
}

Will give:

hello
*NULL*

One use would be in template (meta-)programming: for instance, iterator tags are implemented as empty classes. The only purpose here is to pass around information at compilation time so you can check, if an iterator passed to e.g. a template function meets specific requirements.

EXAMPLE:

This is really simplified, just to ge an idea. Here the purpose of the tag class is to decide, which implementation of an algorithm to use:

class forward_iterator_tag {};
class random_access_iterator_tag {};

class MySimpleForwardIterator {
public:
  typedef typename forward_iterator_tag tag;
  // ...
};

class MySimpleRandomIterator {
public:
  typedef typename random_access_iterator_tag tag;
  // ...
};

template<class iterator, class tag>
void myfunc_int(iterator it, tag t) {
  // general implementation of myfunc
}

template<class iterator>
void myfunc_int<iterator, forward_iterator_tag>(iterator it) {
  // Implementation for forward iterators
}

template<class iterator>
void myfunc_int<iterator, random_access_iterator_tag>(iterator it) {
  // Implementation for random access iterators
}

template<class iterator>
void myfunc(iterator it) {
  myfunc_int<iterator, typename iterator::tag>(it);
}

(I hope I got this right, it's been a while since I used this ...)

With this code, you can call myfunc on an arbitrary iterator, and let the compiler choose the correct implementation depending on the iterator type (i.e. tag).

Tags:

C++

Class