
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