[URL] Variadic Templates, Part I

2 views
Skip to first unread message

/* Alberto Fabiano */

unread,
Aug 26, 2008, 6:49:44 AM8/26/08
to ccppb...@googlegroups.com
Variadic Templates, Part I
http://www.informit.com/guides/content.aspx?g=cplusplus&seqNum=396

TR1's tuple class template allows you to pack an arbitrary number of objects with arbitrary types in a single container-like object. The underlying implementation of class templates that take a variable number of arguments in contemporary C++ is problematic and limiting, though. The addition of variadic templates to C++0x will make the implementation of such classes much simpler, ridding library implementers of many of the limitations and performance bottlenecks that they are facing today. Let's examine variadic templates in detail.

The Problem

The canonical example that demonstrates the need for variadic templates in C++ is class tuple:

tuple<int, float> t2;
tuple<char, string, short, double> t4;

Tuples set an arbitrary limit on the number of arguments they can store. According to the C++0x standard, the minimum number of elements allowed is 10. The reason for specifying such a low minimum is that implementers are unable to directly express in contemporary C++ the notion that a function or class template takes an arbitrary number of arguments. Instead, they use various emulations, including extra defaulted template parameters and preprocessor metaprogramming (Yes, macros are back with a vengeance!). Using the preprocessor to emulate "variadic" templates eliminates a large amount of code duplication that would occur otherwise. However, it comes with many problems. Take for example the std::tr1::function class. The original GCC implementation of that class supported 20 parameters but the excessive compilation time forced the implementers to revert to a maximum of 10 parameters instead. Even with 10 parameters, the code of std::tr1::function still requires too much time to preprocess and parse. In addition, it's nearly unintelligible. Let's look at a concrete example.

To implement a tuple that accepts up to 10 parameters of unrelated types, library vendors use default template parameters, with a dummy struct serving as default value for every parameter:

struct unused;
template<typename T1 = unused, typename T2 = unused, typename T3 = unused,
template<//_ up to _N parameters
typename TN = unused> class tuple;

This tuple can be used with anywhere from zero to n template arguments. However, most of the specializations of that class template will have a large number of unused arguments:

tuple <char, short, int, long long> eightosixtyfourbits;

Here, six template parameters are unused, but they still lead to long compilation times and cryptic compilation errors. One way to optimize the compiler-generated code of such classes is to provide a list of partial specializations as follows:

template<>
class tuple<> { /* zero-argument version*/ };
template<typename T1>

class tuple<T1> { /* single argument version*/ };
template<typename T1, typename T2>
class tuple<T1, T2> { /* two-argument version*/ };

This trick ensures that the code produced for a given number of arguments is optimized and correct. However, it also leads to a huge amount of code repetition and extremely long type names in error messages (many compilers print the defaulted arguments anyway). There is a more serious flaw with this approach -- the fixed upper limit on the number of arguments that can be provided.

To solve these problems, a new C++0x feature called variadic templates was voted into the Working Paper some time ago. Let's see which advantages variadic templates offer.

Variadic Templates

C++0x variadic templates provide an intuitive and efficient mechanism for expressing function and class templates that take an arbitrary number of arguments (in this part I will focus only on variadic class templates). The authors of the variadic templates proposal specifically designed this feature to eliminate the need for most uses of preprocessor meta-programming. In addition, variadic templates are type-safe and improve argument forwarding.

Using this new feature, you can explicitly state that tuple accepts one or more template parameters like this:

template<typename... Elements> class tuple;

The ellipsis (which you probably recognize from printf()-style variable arguments function declarations) to the left of Elements indicates that Elements is a template type parameter pack. A parameter pack is a new notion. Unlike an ordinary parameter, which can only bind to a single argument, a parameter pack is a single identifier grouping zero or more template arguments. Thus, in the following typedef declaration:

typedef tuple <char, short, int, long long> eightosixtyfourbits;

The parameter pack Elements binds to a list of arguments: char, short, int and long long whereas in this declaration, the parameter pack Elements binds to three arguments:

typedef tuple <float, double, long double> floating_point;

In the next part of this series, I will show how to unpack a parameter pack and present variadic function templates.



[ ]s

AF.

Psycho Mantys

unread,
Aug 26, 2008, 1:56:59 PM8/26/08
to ccppb...@googlegroups.com
/* Alberto Fabiano */ wrote:
> Variadic Templates, Part I
> http://www.informit.com/guides/content.aspx?g=cplusplus&seqNum=396
> <http://www.informit.com/guides/content.aspx?g=cplusplus&seqNum=396>
>
> TR1's tuple class
> <http://www.informit.com/guides/content.aspx?g=cplusplus&seqNum=216>
> template allows you to pack an arbitrary number of objects with
> arbitrary types in a single container-like object. The underlying
> implementation of class templates that take a variable number of
> arguments in contemporary C++ is problematic and limiting, though. The
> addition of variadic templates to C++0x will make the implementation
> of such classes much simpler, ridding library implementers of many of
> the limitations and performance bottlenecks that they are facing
> today. Let's examine variadic templates in detail.
>
>
> The Problem
>
> The canonical example that demonstrates the need for variadic
> templates in C++ is class tuple:
>
> tuple<int, float> t2;
> tuple<char, string, short, double> t4;
>
> Tuples set an arbitrary limit on the number of arguments they can
> store. According to the C++0x standard, the minimum number of elements
> allowed is 10. The reason for specifying such a low minimum is that
> implementers are unable to directly express in contemporary C++ the
> notion that a function or class template takes an arbitrary number of
> arguments. Instead, they use various emulations, including extra
> defaulted template parameters and preprocessor metaprogramming (Yes,
> macros are back with a vengeance!). Using the preprocessor to emulate
> "variadic" templates eliminates a large amount of code duplication
> that would occur otherwise. However, it comes with many problems. Take
> for example the std::tr1::function
> <http://www.informit.com/guides/content.aspx?g=cplusplus&seqNum=311>
> class. The original GCC implementation of that class supported 20
> parameters but the excessive compilation time forced the implementers
> to revert to a maximum of 10 parameters instead. Even with 10
> parameters, the code of std::tr1::function still requires too much
> time to preprocess and parse. In addition, it's nearly unintelligible.
> Let's look at a concrete example.
>
> To implement a tuple that accepts up to 10 parameters of unrelated
> types, library vendors use default template parameters, with a dummy
> struct serving as default value for every parameter:
>
> struct unused;
> template<typename T1 = unused, typename T2 = unused, typename T3 = unused,
> template<//_ up to _N parameters
> typename TN = unused> class tuple;
>
> This tuple can be used with anywhere from zero to n template
> arguments. However, most of the specializations of that class template
> will have a large number of unused arguments:
>
> tuple <char, short, int, long long> eightosixtyfourbits;
>
> Here, six template parameters are unused, but they still lead to long
> compilation times and cryptic compilation errors. One way to optimize
> the compiler-generated code of such classes is to provide a list of
> partial specializations
> <http://www.informit.com/guides/content.aspx?g=cplusplus&seqNum=50> as
> follows:
>
> template<>
> class tuple<> { /* zero-argument version*/ };
> template<typename T1>
>
> class tuple<T1> { /* single argument version*/ };
> template<typename T1, typename T2>
> class tuple<T1, T2> { /* two-argument version*/ };
>
> This trick ensures that the code produced for a given number of
> arguments is optimized and correct. However, it also leads to a huge
> amount of code repetition and extremely long type names in error
> messages (many compilers print the defaulted arguments anyway). There
> is a more serious flaw with this approach -- the fixed upper limit on
> the number of arguments that can be provided.
>
> To solve these problems, a new C++0x feature called /variadic
> templates/ was voted into the Working Paper some time ago. Let's see
> which advantages variadic templates offer.
>
>
> Variadic Templates
>
> C++0x /variadic templates/ provide an intuitive and efficient
> mechanism for expressing function and class templates that take an
> arbitrary number of arguments (in this part I will focus only on
> variadic class templates). The authors of the variadic templates
> proposal specifically designed this feature to eliminate the need for
> most uses of preprocessor meta-programming. In addition, variadic
> templates are type-safe and improve argument forwarding.
>
> Using this new feature, you can explicitly state that tuple accepts
> one or more template parameters like this:
>
> template<typename... Elements> class tuple;
>
> The ellipsis (which you probably recognize from printf()-style
> variable arguments function declarations
> <http://www.informit.com/guides/content.aspx?g=cplusplus&seqNum=138>)
> to the left of Elements indicates that Elements is a template type
> /parameter pack/. A parameter pack is a new notion. Unlike an ordinary
> parameter, which can only bind to a single argument, a parameter pack
> is a single identifier grouping zero or more template arguments. Thus,
> in the following typedef declaration:
>
> typedef tuple <char, short, int, long long> eightosixtyfourbits;
>
> The parameter pack Elements binds to a list of arguments: char, short,
> int and long long whereas in this declaration, the parameter pack
> Elements binds to three arguments:
>
> typedef tuple <float, double, long double> floating_point;
>
> In the next part of this series, I will show how to unpack a parameter
> pack and present variadic function templates.
>
>
>
> [ ]s
>
> AF.
>
> >
##############################################################################################

Queria ver o unpack dos parametros .... :'(.

Isso é muito legal. Seria um bom incremento na linguagem.
Mas tem alguma coisa de ruim nisso? Pelo menos eu não vi. Dependendo de
como ele faça o unpack dos parametros, isso vai ajudar pra caramba...


P.

unread,
Aug 26, 2008, 2:37:33 PM8/26/08
to ccppbrasil
On 26 ago, 14:56, Psycho Mantys <psycho.man...@gmail.com> wrote:

> Queria ver o unpack dos parametros .... :'(.
>
> Isso é muito legal. Seria um bom incremento na linguagem.
> Mas tem alguma coisa de ruim nisso? Pelo menos eu não vi. Dependendo de
> como ele faça o unpack dos parametros, isso vai ajudar pra caramba...

Será um bom incremento, já que muito provavelmente variadic templates
não será _retirado_ do draft do C++0x. :-)

O unpack dos parâmetros acontece através da especialização parcial do
template. O processo é um típico processo recursivo, em que uma
especialização total para a "lista vazia" e uma especialização parcial
para "elemento, resto da lista" são providenciadas. Quando o template
é usado com uma lista não-vazia de argumentos de template, a
especialização parcial "elemento, resto da lista" é selecionada; esta
especialização deve fazer uso do elemento e instanciar-se novamente
com o resto da lista; eventualmente a lista se tornará vazia e a
especialização total será selecionada.

O GCC 4.3 possui uma implementação de variadic templates acessível com
o flag --std=gnu++0x na linha de comando.

--
P.

Psycho Mantys

unread,
Aug 26, 2008, 4:31:26 PM8/26/08
to ccppb...@googlegroups.com
####################################################################################################

Será um bom incremento, já que muito provavelmente variadic templates
não será _retirado_ do draft do C++0x. :-)


:p.

O unpack dos parâmetros acontece através da especialização parcial do
template. O processo é um típico processo recursivo, em que uma
especialização total para a "lista vazia" e uma especialização parcial
para "elemento, resto da lista" são providenciadas. Quando o template
é usado com uma lista não-vazia de argumentos de template, a
especialização parcial "elemento, resto da lista" é selecionada; esta
especialização deve fazer uso do elemento e instanciar-se novamente
com o resto da lista; eventualmente a lista se tornará vazia e a
especialização total será selecionada.

O GCC 4.3 possui uma implementação de variadic templates acessível com
o flag --std=gnu++0x na linha de comando.


Rapaz, valeu Pedro, entendi mais ou menos o que você falou, mas não
tinha conseguido "visualizar" nada como ficaria o codigo.
Por isso dei uma procuradinha extra :D.
http://www.generic-programming.org/~dgregor/cpp/variadic-templates.html
Esse link explica e demostra o "variadic template" melhor, para quem
quiser "ver" :D.


Thiago Adams

unread,
Aug 26, 2008, 5:06:03 PM8/26/08
to ccppbrasil
Tentando explicar com outras palavras..
Basicamente a especialização parcial para N chama a especialização
para N - 1 argumentos.
Ela para quando alguma delas não chamar mais a N – 1. A que faz isso
geralmente será a especialização para N = 0, que é uma especialização
completa.
Para quem se confunde com estes termos especialização completa e
parcial é o seguinte.
Uma especialização completa é aquela em que todos os tipos necessários
para instanciar o template já estão definidos. (Você não verá nenhum
tipo faltando na lista do template)
A especialização parcial é aquela que ainda tem um ou mais tipos a
serem definidos, ou seja, a lista dos parâmetros do template não é
vazia.

Alan Silva

unread,
Aug 27, 2008, 1:18:43 PM8/27/08
to ccppb...@googlegroups.com
Sim,

Inclusive o paper da proposta é bem interessante e vale a pena uma lida... :D

http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2004/n1704.pdf

[ ] 's

Alan

2008/8/26 Thiago Adams <thiago...@gmail.com>

wander

unread,
Sep 1, 2008, 1:29:57 PM9/1/08
to ccppbrasil
Já saiu a segunda parte do artigo:

http://www.informit.com/guides/content.aspx?g=cplusplus&seqNum=397&f1=rss

Wander

On 27 ago, 14:18, "Alan Silva" <alan.si...@gmail.com> wrote:
> Sim,
>
> Inclusive o paper da proposta é bem interessante e vale a pena uma lida...
> :D
>
> http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2004/n1704.pdf
>
> [ ] 's
>
> Alan
>
> 2008/8/26 Thiago Adams <thiago.ad...@gmail.com>
Reply all
Reply to author
Forward
0 new messages