What could be the possible advantages/uses of having an empty class?
P.S: This question might sound trivial to some of you but it is just for learning purpose and has no practical significance. FYI googling didn't help.
What could be the possible advantages/uses of having an empty class?
P.S: This question might sound trivial to some of you but it is just for learning purpose and has no practical significance. FYI googling didn't help.
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 randomaccess_iterator_tag {};
class MySimpleForwardIterator {
public:
typedef typename forward_iterator_tag tag;
// ...
};
class MySimpleRandomIterator {
public:
typedef typename randomaccess_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, randomaccess_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).
An empty class could be used as a "token" defining something unique; in certain patterns, you want an implementation-agnostic representation of a unique instance, which has no value to the developer other than its uniqueness. One example is Unit of Work; you may not care one bit about what's going on inside your performer, but you want to tell that performer that the tasks you're telling it to perform are part of an atomic set. An empty class representing the Unit of Work to the outside world may be perfect in this case; almost anything a Unit of Work object could store or do (encapsulating a DB transaction, exposing Commit/Rollback behaviors) would start tying you to a particular implementation, but an object reference is useful to provide a unique but copyable and passable reference to the atomic set of tasks.
"empty" classes means classes which have no data members? They typically declare typedefs or member functions, and you can extend them with your own classes.
(ignore this: All I can think of is pure virtual classes with no members to be used as generic place-holders.)
Just found this: to test if your compiler is good at optimizing
In the link above he says at the end: " ... is safe and can be most useful. It allows a programmer to use empty classes to represent very simple concepts without overhead."
Now what does that mean?
Here is an interesting link with answers to why its allowed. You might find this helpful to find situations where it might be useful.
You can use it like a placeholder for checking purpose or as enabler to special functionality. For example in Java exist the "empty" interface Serializable used to specify if a class is serializable.
In the STL, Standard Template Library of the C++, for example you have
template<class _Arg,
class _Result>
struct unary_function
{ // base class for unary functions
typedef _Arg argument_type;
typedef _Result result_type;
};
When defining a functor, you can inherit unary_function, and then you have the typedef defined automatically at your disposal.
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*
As others have said, often an empty class (or struct) is used a placeholder, a differentiator, a token, etc.
For example, a lot of people are unaware that there are "nothrow" versions of operator new. The syntax to invoke nothrow new is:
p = new(std::nothrow) Bar;
and std::nothrow is defined simply as
struct nothrow_t {}; //defined in namespace std