|
Boost : |
From: Doug Gregor (dgregor_at_[hidden])
Date: 2006-08-04 17:54:25
Hello Fellow Boosters,
I have just completed implementing support for "Variadic Templates"
in GCC. Variadic templates are C++ templates that can accept any
number of "extra" template arguments, just like a function that uses
C-style varargs (with "...") can accept any number of extra
arguments. Unlike C varags, however, variadic templates work both for
class templates and function templates, and are completely type-safe.
Why do variadic templates matter for Boost? For one thing, they will
allow us to eliminate the use of preprocessor metaprogramming in
many, many places throughout the library. This can simplify our
library implementations drastically, and eliminate those annoying
"caps" on the number of arguments one can use (ever tried to use bind
() with 11 arguments?). Beyond that, variadic templates are just
plain fun, and there are undoubtedly a great number of
metaprogramming applications. Here are a few teasers to illustrate
what variadic templates can do:
We can implement an MPL-like type vector with one line of code:
template<typename... Types> struct vector { };
The "ellipsis" means that we can pack any number of arguments into
the "template parameter pack" called Types.
Of course, we can do the same for MPL's vector_c:
template<typename T, T... Values> struct vector_c { };
Unimpressed? Here's an implementation of tuple that accepts any
number of element types:
template<typename... Values>
class tuple;
template<> class tuple<> { };
template<typename Head, typename... Tail>
class tuple<Head, Tail...>
: private tuple<Tail...>
{
protected:
Head m_head;
};
We're using recursion to build up the tuple. The ellipsis operator
works with partial specializations, too, packing together "extra"
arguments at the end. Of course, all of this would be useless if we
couldn't write some of the other tuple operations, like operator==:
inline bool operator==(const tuple<>&, const tuple<>&) { return
true; }
template<typename T, typename... TTail, typename U, typename...
UTail>
bool operator==(const tuple<T, TTail...>& t, const tuple<U,
UTail...>& u)
{
return t.head() == u.head() && t.tail() == u.tail();
}
Variadic function templates can accept any number of function
arguments, so we can now (finally!) implement a type-safe printf()
without mangling the tried-and-true printf() syntax or restricting
ourselves to POD types:
void printf(const char* s) {
while (*s) {
if (*s == '%' && *++s != '%')
throw std::runtime_error("invalid format string: missing
arguments");
std::cout << *s++;
}
}
template<typename T, typename... Args>
void printf(const char* s, const T& value, const Args&... args) {
while (*s) {
if (*s == '%' && *++s != '%') {
std::cout << value;
return printf(++s, args...);
}
std::cout << *s++;
throw std::runtime_error("extra arguments provided to printf");
}
I've also built prototypes of of Function and Bind, among other
things. The Bind example is especially interesting, and worth a read
(see below)
Interested? There is more information and a complete implementation
in GCC available at:
http://www.generic-programming.org/~dgregor/cpp/variadic-
templates.html
I've written two documents describing variadic templates in more detail:
http://www.generic-programming.org/~dgregor/cpp/brief-intro.pdf :
A brief introduction to variadic templates, that walks through the
printf() implementation.
http://www.generic-programming.org/~dgregor/cpp/variadic-
templates.pdf : A complete proposal to introduce variadic templates
into C++0x. This contains annotated versions of the tuple, function,
and bind prototypes along with a detailed description of the
capabilities of variadic templates.
The GCC implementation is complete, supporting all of the features
described in the proposal. I've used it for proof-of-concept
implementations of several libraries. In the (near) future, I hope to
introduce variadic templates support into the "official" GCC, but I
need your help!
Are variadic templates worthwhile? Will they help us build better,
cleaner Boost libraries in the future? Should we bring variadic
templates to the C++ committee, to enable better implementations of
TR1 components and eliminate the need for much of the preprocessor
metaprogramming we do today? Feedback is greatly appreciated.
Cheers
Doug Gregor
Open Systems Lab @ Indiana University
Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk