Você está na página 1de 392
This document was created by an unregistered ChmMagle, please go to hitp:/Awww.bisenter.com to register I, Thanks oe (See) ties Metaprogramming Ce) eI PT IA ee (Fah) 23 from Boost and Beyond David Abrahams Aleksey Gurtovoy C++ In-Depth Series ¢ Bjarne Stroustrup + Fate ot Content C++ Template Metaprogramming: Concepts, Tols, and Techniques trom Boost and Beyond By David Abraham feksey Gurtovo Publisher: Adelson Wesley Professional Pub Date: December 10, 2004 ISBN: 0-321-22725-5 Pages: 400 Ifyou like me, you'e excited by what people do with tempate melaprogramming (TMP) but are frustrated atthe lack of clear Powerful tools. Wel thsi the book we've been waiting for. With help from the excellent Boost Metaprogramming fake TMP from the laboratory tothe workplace wih readable prose and practical examples, showing This document was created by an unregistered ChmMagle, please go to hitp:/Awww.bisenter.com to register it. Thanks that ‘compile-time STL"is as abe as its runtime counterpart. Serving as a tutorial as well as @ handbook for experts, this isthe book (on C++ template metaprogramming "Chuck Alison, Editor, The C++ Source (C++ Template Metaprogramming sheds light on the most powertul idioms of today’s C++, at long last delivering practical ‘metaprogramming tools and techniques into the hands of the everyday programmer. ‘A metaprogram isa program that generates or manipulates program code. Ever since generic programming was introduced to C++, programmers have discovered myriad "template tricks" for manipulating programs as they are compiled, effectively eliminating the barrier between program and metaprogram. Wile excitement among C+ experts about these capabilities has reached the ‘community at large, their practical application remains out of reach for most programmers, This book explains what metapragrammingis and haw itis best used, I proves the foundation youll need to use the template metapregramming effectively in your own work. ‘his book is aimed at any programmer who is comfortable with idioms ofthe Standard Template Library (STL). C++ power-users will gain anew insight nto their existing work and a new fluency in the domain of metaprogramming.Intermeciate-level programmers who have learned a few advanced template techniques wil see where these tricks fit inthe big picture and will gain the conceptual foundation to use them wih discipline. Programmers who have caught the scent of metaprogramming, but for whom itis stil mysterious, wil finaly gain a clear understanding of how, when, and why it works. All readers wil leave wth a new tool of unprecedented power at ther disposalthe Boost Metaprogramming Library. “The companion CD-ROM contains all Boost C++ libraries, including the Boost Metaprogramming Library and is reference {documentation along with all ofthe book's sample code and extensive supplementary materia, This document was created by an unregistered ChmMagio, please go to http:/Aww.bisenter.com to register it Thanks (C++ Template Metaprogramming: Concepts, Tools, and Techniques from Boost 8y David Abraham leksey Gurtovo Publisher: Addison Wesley Professional a Pub Date: December 10, 2004 ISBN: 0-821-227255 Pages: 400 antent ooyrigh he Gx In-Depth Serie ites in the Serie iaking the Most of This Book Pupotementay Material ‘ying h Out hapter 1. Introduction ection 1.1. Getting Stare bection 1.2, So What's a Metaprogram’ Becton 1.7, Why a Metaproqramming Libary] hapter 2, Traits and Type Manipulation) so Lanes nai hs document was created by an unregistered ChmMagic, please go to http:s/wmw.bisente.com to register it. Thanks| ‘Sequences and Algorithms Iterator ection 5.5. Sequence Concept ecion5.6. Sequence Equal ection 5.7. Invinsic Sequence Operations ecion’.8. Sequence Classe ection 5.0. Intearal Sequence Wrapper eciion5.10. Sequence Derivation Your Own View) ection 7.5. Hist Beciion 7.6. Exercise hapler 8. Diagnostied ection 8.1. Debugging the Error Nove “Tools for Diagnostic Analyst Histo Detail Tgp 9_Crssig he Connie Tie Rie Ban Pasir eae Piston 2 inpenenaion Seo Fsion93- open Goma elon Scar Soto pas Sea Pisin 0 Wenney funn Pablo Tepe Rone Pisiono7 Toe Easud Pisin 6 Tne cuss desu Tenge Pa Bection 29, Explcty Managing the Overload Se hs document was created by an unregistered ChmMagic, please go to http:s/wmw.bisente.com to register it. Thanks| ection 9.10. The “sizeot Tice fection 9.11. Summar hapler 10. Domain-Specific Embedded Language Becton 10.1. A Litte Language ection 10.2... Goes a Long Way ection 10.3. DSIs, Inside Oul (Ci as the Host Langues ection 10.5, Bltze+ and Expression Template] ection 10.6. General Purpose DSEL: ection 10.7. The Boost Sprit Libran hapter 1A DSEL Design Walkthrouah] Direotior pendix A._An introduction to Preprocessor Metapragramming Becton A.1. Motivation Becton AZ, Fundamental Abstractions ofthe Preprocesso| [ection A.4. Preprocessor Library Abstraction Beciion AS. Exercss Aopencix 8. The typename and template Keywor ection 8.1. The issu ection 8.2, The Rule fropendix D. MPL Portability Summa D-ROM Warrant Bioiograph This document was created by an unregistered ChmMagle, please go to hitp:/Awww.bisenter.com to register it. Thanks Copyright Many ofthe designations used by manulacturers and sellers to distinguish their products are claimed as trademarks. Where those esignations appear inthis book, and Addison-Wesley was aware of a trademark claim, the designations have been printed with inal capital letters or in al capitals ‘The authors and publisher have taken cafe inthe preparation ofthis book, but make no expressed or implied warranty of any kind {and assume no responsibity for errors or omissions. No labilly is assumed for incidental or consequential damages in connection with or arising out ofthe use ofthe information or programs contained herein. ‘The publisher offers ciscounts on this book when ordered in quantty for bulk purchases and special sales. For more information, please contact: U.S. Corporate and Government Sales orpsales @pearsonlechgroup cr For sales outside the U.S., please contact International Sal lnternational@pearsoned con] Vist Addison-Wesley on the Web: [maw awprofessional.con] ‘Library of Congress Cataloging-in-Publcation Data Abrahams, Davi. (C++ template metaprogramming: concepts tools, and techniques from Boost and beyond / David Abrahams, Aleksey Gurtovoy. pom ISBN 0-821-22725-5 (pbi-: alk paper) 1. C++ (Computer program language) 2. Computer programming. |. Gutovoy, Aleksey. I Tie (QA 76.73.01834825 2004 (005.133 —ic22 2004017580 Copyright ©2005 by Pearson Education, Inc. All rights reserved. No part ofthis publication may be reproduced, stored ina retrieval system, or transmitted, in any form, or by any means, electronic, mechanical, photocopying, recording, or otherwise, without the prior consent of the publisher. Pinte inthe United States of America. Published simultaneously in Canada, For information on obtaining permission for use of material from this wor, please submit a written request to: Pearson Education, Inc. Rights and Contracts Department Le document was created by an unregistered ChmMagic, please go to http:/wm.bisente.com to register it. Thanks| 76 Arlington Street, Suite 300 Boston, MA 02116 Fax: (617) 848-7047 Tex printed on recycled paper 123456789 10~CRS—0807060504 First printing, November 2004 Top = This document was created by an unregistered ChmMagle, please go to hitp:/Aww.bisenter.com to register it. Thanks The C++ In-Depth Series Bjame Stroustrup, Editor "have made ths eter longer than usual, because | lack the time to make it shor.” —BLAISE PASCAL ‘The advent ofthe ISO/ANSI C+ standard marked the beginning of a new era for C++ programmers. The standard offers many new facilities and opporturites, but how can a real-world programmer ind the time to discover the Key nuggets of wisdom within this ‘mass of information? The C++ In-Depth Series minimizes learning time and confusion by giving programmers concise, focused (uides to specific topics. Each book inthis series presents a single topic, at a technical level appropriate to that topic. The Series’ practical approach is Cesigned to lit professionals to their next evel of programming sis. Written by experts in the field, these shor, in-depth ‘monographs can be read and referenced without the distraction of unrelated material. The books are cross-elerenced within the Series, and also reference The C++ Programming Language by Bjarne Stroustrup, [As you develop your skils in C+, it becomes increasingly important to separate essential information trom hype and glitz, and to find the in-depth content you need in otder to grow. The C++ In-Depth Series provides the tools, concepts, techniques, and new approaches to C++ that wil give you a crtical edge. Top = This document was created by an unregistered ChmMagle, please go to hitp:/Aww.bisenter.com to register it. Thanks Titles in the Series Accelerated C++: Practical Programming by Example Andrew Koenig and Barbara E. Moo Applied C++: Practical Techniques for Building Better SoftwarePrilip Romani and Amy Muntz ‘The Boost Graph Library: User Guide and Reference Manual Jeremy G. Siek, Lie-Quan Lee, and Andrew Lumsdaine (C++ Coaing Standards: 101 Rules, Guidelines, and Best Practices Herb Sutter and Andrei Alexandrescu 2+ In-Depth Box Set, Bjarne Stroustrup, Andrel Alexandrescu, Andrew Koenig, Barbara E. Moo, Stanley B, Lippman, and Hert Suter (+4 Network Programming, Volume 1: Mastering Complexity wth ACE and PattersDougls C. Schmidt and Stephen D. Huston +4 Network Programming, Volume 2: Systematic Reuse with ACE and FramewerksDauglas C. Schmist and Stephen D. Huston +4 Template Metaorogramming: Conceps, Toots, and Techniques trom Boost and BeyondDavié Abrahams and Aleksey Gurtovoy Essential C+, Stanley B. Lippman ‘Exceptional C++: 47 Engineering Puzzles, Programming Problems, and Solutions Herb Sutter Exceptional G++ Style: 40 New Engineering Puzzles, Programming Problems, and Solutions Herb Sutter ‘Moder C+ Design: Generic Programming and Design Patterns Applied Andel Alexandrescu ‘More Exceptional C++ 40 New Engineering Puzzles, Programming Problems, and Solutions Herb Sutter For mor information, check out the series web ste aly awprofessional.comseries/indepth Top = This document was created by an unregistered ChmMagle, please go to hitp:/Aww.bisenter.com to register it. Thanks Preface 1 1998 Dave had the privilege of attending a workshop in Generic Programming at Dagstuh! Castle in Germany. Near the end of the workshop, a very enthusiastic Kristof Czamecki and Ulich Eisenecker (of Generative Programmingtame) passed out afew ages of C++ source code that they billed asa complete Lisp implementation bul out of C++ templates. At the time it appeared to DDave to be nothing more than a curiosity, a charming but impractical hijacking ofthe template system to prove that you can write programs that execute at compile ime. He never suspected that ane day he would see a rle for metaprogramming in most of his day-to-day programming jobs. In many ways, that collection of templates was the precursor to the Boost Metaprogramming Library (MPL may have been the fist brary designed to turn compilime C++ from an ad hoc collection of "template tricks" into an ‘example of disciplined and readable software engineering. With the availabilty of tools to write and understand metaprograms at a high level, we've since found that sing these techniques isnot only practical, but easy, fun, and often astoundingly powerful Despite the existence of numerous real systems built with template metaprogramming and the MPL, many people stil consider ‘metaprogramming o be other-worily magic, and often as something to be avoided in day-to-day production cade. If youve never done any metaprogramming, t may not even have an obvious relationship tothe work you do. With ths book, we hope to lit the vel cof mystery, so that you get an understanding not only of how metaprogramming is done, but also why and when. The best pat is that white much of the mystery will have dissolved, we think youl sil ind enough magic let in the subject to stay as inspired about itas we are. Dave and Aleksey This document was created by an unregistered ChmMagle, please go to hitp:/Aww.bisenter.com to register it. Thanks Acknowledgments \We thank our reviewers, Douglas Gregor, Joel de Guzman, Maxim Khesin, Mat Marcus, Jeremy Siek, Jaap Suter, Tommy ‘Svensson, Danie! Walin, and Leor Zolman, for keeping us honest. Special thanks goto Luann Abrahams, Brian McNamara, and Etic Niele, who read and commented on evary page, often when the material was stil very rough. We also thank Vesa Karvonen and Paul Mensonides for reviewing AppendicAlin detail For their fait that we'd wrte something of value, we thank our editors, Peter Gordon and Bjame Stroustrup. David Goodger and Englebert Gruber buil the ReStructuredText markup language in which this book was written. Final, we thank the Boost community fr creating the environment that made our colaboration possible. Top = This document was created by an unregistered ChmMagle, please go to hitp:/Aww.bisenter.com to register it. Thanks Dave's Acknowledgments In February of 2004 | used an early version ofthis book to give a couse fora brave group of engineers at Oerikon Contraves, In. Thanks to all my students for struggling through the tough parts and giving the material a goed shakedown, Special thanks go to jean Senecal for making that investment high-performance code with along future, against the tide ofa n-investment mentally CChuck Alison, Scott Meyers, and Herb Sutter have all encouraged me to get more of my work in pint—thanks guys, hope this is a (ood start |/am grateful to my coleagues on the C++ standards committee and at Boost for demonstrating that even with egos and reputations a stake, technical people can accomplish great things in collaboration. Its hard to imagine where my career would be today without these communes. | know this book would nat have been possible without them, Final, for taking me to see the penguins, and fr reminding me to think about them atleast once per chapler, my fondest thanks go to Luann, oo Top = This document was created by an unregistered ChmMagle, please go to hitp:/Aww.bisenter.com to register it. Thanks Aleksey's Acknowledgments [My special thanks go to my teammates at Meta for being my “extended family" forthe past ve years, and for creating and ‘maintaining the mast rewarding work environment ever. A fair amount of Knowledge, concepis, and ideas rellected inthis book were shaped during the pair programming sessions, seminars, and casual insightful discussions that we held here. | also would ike to thank all the people who in one or anther way contributed to the development ofthe Boost Metaprogramming Library—the tool that in same sense this book's centered around, There are many of them, but in particular, John R. Bandela, Fernando Cacciola, Peter Dimov, Hugo Duncan, Eric Friedman, Douglas Gregor, David B. Held, Vesa Karvonen, Mat Marcus, Paul Mensonides, Jaap Suter, and Emily Winch all deserve a special thank you. My friends and family provided me with continued encouragement and support, and it has made a big diference in this journey—thank you all so much! Las but not least, thank Julia for being herself, for believing in me, and for everything she has done for me. Thank you for everything oo Top = This document was created by an unregistered ChmMagle, please go to hitp:/Aww.bisenter.com to register it. Thanks Making the Most of This Book ‘The first few chapters ofthis book lay the conceptual foundation youll need for most everything else we cover, and chapters generally uid on material that has come before. That said feel ree to skip ahead for any reason—we'e tried to make that possible by providing cross-references when we use tems inttoduced eater on. aoter 1(] Domain-Specific Embedded Languages, is an exception tothe rule that later chapters depend on eater ones. It focuses mostly on concepis, and only appears late inthe book because at that point youll have eamed the tools and techniques to put Domain-Specitic Embedded Languages into pla in real code. Ifyou only remember one chapter by the time you're done, make itthat one. Near the end of many chapters, rep Dts section that summarizes key ideas. These sections usually add new material that deepens the earlier discussion, them later. so even ifyou are inclined to skim them the fst ime through, we suggest you refer back to we oe idea from Andrew Koenig and Barbara Moo'secelerated C++: Pr Programming By Exampl We conclude most chapters with exercises designed to help you develop bath your programming and conceptual muscles. Those marked with asterisks are expected to be more of a workout than the others. Not all exercises involve writing code—some could be considered "essay questions'—and you don’ have to complete them in order to move on to later chapters. We do suggest you look through them, give alte thought to how you'd answer each one, and try your hand atone or two; its a great way to gain confidence with what you've just read. oo Top = This document was created by an unregistered ChmMagle, please go to hitp:/Aww.bisenter.com to register it. Thanks Supplementary Material This book comes with a companion CD that supplies the following items in electronic form © Sample code trom the book © Arelease of the Boost C++ libraries. Boost has become known for high-qually, peer-reviewed, portable, generic, and freely reusable C++ libraries. We make extensive use of one Boas! library throughout the book—the Boost Metaprogramming Library (MPL|—and we discuss several others. (© A-complete MPL reference manual, in HTML and POF form © Boost aries discussed inthis book that are not yet part ofan oficial release, The indeschiml fle tthe top level ofthe CD wil provide you with @ convenient guide to allots contents, Addiional and updated ‘material, including the inevitable erat will appear onthe book's Web site: ito:/www.boost-consulting.comimplbooX). You also find place there to report any mistakes you might find. This document was created by an unregistered ChmMagle, please go to hitp:/Aww.bisenter.com to register it. Thanks Trying It Out To compile any ofthe examples, just put the CD ‘boost |_82_0/ directory into your compiler’ include path ‘The libraries we present in this book goto great lengths to hide the problems of less-thar-pertect compilers, so i's unlikely that yout have trouble withthe examples we present here. That sal, we dvide C++ compilers roughly ino three categories. 'A. Those with mostly conforming template implementations. On these compilers, the examples and libraries "ust work. ‘Almast anything released since 2001, and a few compilers released before then, fal nt this category. BB. Those that can be made to work, but require some workarounds in user code. {C._ Those that are too broken to use effectively for template metaprogramming. [appendix d]ists the compilers that are known to fall into each ofthese categories. For those in category Appendix refers to alist ‘of portabily idioms. These idioms have been applied tothe copies ofthe book's examples that appear onthe accompanying CD, but to avoid distracting the majority of readers they don’ appear inthe main text ‘The CD also contains a portabity table with a detaled report of how various compilers are doing with our examples. GCC is available tree for most platforms, and recent versions have no problems handing the code we present here. Even ou vere mada cpr tom ctr righ bea gon ia io rab a copy GC wih whch tunoceckyourcoe-Oten te eases ao oop an Tela on message lo ee wal sone det compe as intmaing { sld:cout << binary<101010>::value << std:endl return 0; Evenif you were always good at binary arithmetic and can tell what the output ofthe program willbe without actually unning it, we sti suggest that you go othe trouble of tying to compile and run the example. Besides contributing to building your confidence, its ‘2 good test of whether your compilers abe to handle the code we present inthis book. The program should write the decimal value of the binary number 101010: 2 to the standard output Top = This document was created by an unregistered ChmMagle, please go to hitp:/Awww.bisenter.com to register it. Thanks 1.2. So What's a Metaprogram? you dette word metaprogram ey tmeansa program sboita prea TA tess posal a meapogam isa progam al mares code mayb ano suring conc bl ou proba ety ana wi sv sa beads Your Ors compt bone tanplerttmryaiaae yr Ct coe pice amend gape maine coe in philosophy and, as it happens, programming, the prefix “meta’ is used to mean “about” or “one level of description higher,” as deived from the original Greek meaning “beyond” or “behind” Parser generators such as VACC|oi79] are another kind of program-manipulating program. The input to YACC is a high-level parser description written in terms of grammar rules and attached actions brace-enclosed. For instance, to parse and evaluate atthmetc expressions wit the usual precedence rules, we might feed YACC the following grammar description: ‘expression: term | expression + term ($8 =$1 + $3;) | expression ~ term ($8 = $1 -$3;) term :facor Item" factor ($6 = $1 *$3;) [term ? factor ($8 = $1 /$3:) factor: INTEGER | group ‘group :'( expression Inresponse, YACC would generate a CiC++ source fle containing (among other tings), a yyparse function that we can call to parse text against the grammar and execute the appropriate actions! {21 This is provided that we also implemented an appropriateyylex function to tokenize the text. See[chapter| fora complete example o, better yet, pick up a YACC manual. int main) t extern int yyparse() retum yyparse(); ) Le document was created by an unregistered ChmMagic, please go to http:/wm.bisente.com to register it. Thanks| ‘The user of YACC is operating mostly inthe domain of parser design, so we'll call YACC’s input language the domain language of this system. Because the rest of the users program typically requires a general-purpose programming system and mus interact withthe generated parser, YACC transiates the domain language into the host language, C, which the user then compiles and links together with her other code. The domain language thus undergoes two translation steps, andthe user is aways very conscious of the boundary between itand the rest of her program, oo Top = This document was created by an unregistered ChmMagle, please go to hitp:/Aww.bisenter.com to register it. Thanks 1.3. Metaprogramming in the Host Language YACC is an example of atranslator—a metaprogram whose domai Je difers trom its host language. A more interesting form of metaprogramming is avaliable in languages such as Scheme The Scheme metaprogrammer defines her domain language as a subse o the legal programs in Scheme itselt and the melaprogram execute inthe same translation step used to process the rest ofthe user's program. Programmers move between ordinary programming, metapregramming, and wring inthe domain language, often without being aware ofthe transition, and they are able to seamlessly combine multiple domains in the same system ‘Amazingly, it you have a C++ comple, this is precisely the kind of metaprogramming power you holdin your fingertips. The est of this book is about unlocking that power and showing how and when to use it oo Top = This document was created by an unregistered ChmMagle, please go to hitp:/Awww.bisenter.com to register it. Thanks 1.4. Metaprogramming in C++ In C+s, itwas discovered almost by accident[Unrune4] [veld95b] thatthe template mechanism provides arch faciity for native language metaprogramming. In tis secon well explore the basic mechanisms and some common idioms used for ‘metaprogramming in C+. 1.4.1 Numer Computations ‘The eatlest C++ metaprograms performed integer computations at compile time. One ofthe very fist metaprograms was shown at C+ commitee meeting by Envin Unruh: twas actually an ilegal code fragment whose error messages conlained a sequence of computed prime numbers! Since ilegal code is hard to use effectively ina larger system, les examine a sightly more practical application. The fllowing rmetaprogram (which lie atthe heart of our litle compiler test above) transiterates unsigned decimal numeral into ther binary equivalents, allowing us to express binary constants in a recagnizale form, template stuct binary t static unsigned const value binaryeN/10>:value << 1! prepend higher bits [NMt0; sito lowest bit k template <> 1 specialization uct binary<0> ‘terminates recursion t static unsigned const value = 0; k unsigned const one unsigned const three = binary >:value; unsigned const fve = binary<101>:¥value; unsigned const seven = binarye1 11>:value; unsigned const nine ~ binary<1001>::value; binaryet>:value It yout wondering ‘Where's the program?" we ask you to consider what happens when we access the nested value member of binaryeN>. The binary template is instantiated again with a smalletN, unt N reaches zero and the specialization is used as a termination condition. That process should have the familar flavor ofa recursive function cal'—and what s a program, after all, but function? Essentially the compile is being used to interpre our litle metaprogram. This document was created by an unregistered ChmMagic, please goto http:s/wmw.bisenter.com to register it. Thanks Error Checking ‘There's nothing o prevent a user trom passing binary @ number such as678, whose decimal representation is not also vali binary. The result would make a strange sort of sense Ut would be 6x2" 7x2" + 8:2"), but nonetheless, an input ike 678 probably indicates a bug inthe users logic. lfohapter Jwell show you how to ensure that binary-vaue only compiles when N's decimal representation is composed solely os and 1s. Because the C++ language imposes a distinction between the expression of compile-time and runtime computation, metaprograms look ctferent from their runtime counterparts. As in Scheme, the C+-+ metapragrammer writes her code in he same language as the ordinary program, but in C++ only the compile-time subset ofthe fll language is availabe to her. Compare the previous example wi this straightforward runtime version of binary: unsigned binary(unsigned long N) t return ) 070: N%10 +2" binary(N'10); ‘Akay dtference between the runtime and compile time versions i the way termination conditions are handled: our meta-binary Uses template specialization to describe what happens when is zero. Terminating specializations are a common characteristic of neatly all C++ metaprograms, though in some cases they willbe hidden behind the interface ofa metaprogramming library. Another important citference between runtime and compile time C++ is highlighted by ths version of binary, which uses ator loop in lev of recursion unsigned binary(unsigned long N) t Unsigned resl {or (unsigned bit = Oxt; N;N/= 10, bit >'# >> exrlexprval +=_1]) | (termfexpe.val =_1] >>" >> exprexprval-=_1]) [termfexprval =_1] term = (factor(tem.val =_1] >>" >> termterm.val | (factorterm val =_1] >> 7 >> temitem.val 1) a) Each assignment stores a function object that parses and evaluates the bit of grammar on its right hand side. The behavior of each stored function object, when invoked, is determined entirely by the type of the expression used to construct, and the type of each ‘expression is computed by 2 metaprogram associated with the various operators used. ust ike YACC, the Spirt sary is a metaprogram that generates parsers from grammar specications. Unlike YACC, Spirit defines its domain language as a subset of C++ itsell. I you don't see how that's possibe at this point, dont worry. By the ime you finish this book, you wil Top = This document was created by an unregistered ChmMagle, please go to hitp:/Aww.bisenter.com to register it. Thanks This document was created by an unregistered ChmMagle, please go to hitp:/Awww.bisenter.com to register it. Thanks 1.5. Why Metaprogramming? So, what are the benefits of metaprogramming? There are definitely simpler ways to ackiress the same kinds of problems we've been discussing here. Lets take a look at two other approaches and see how they stack up wien apaled tothe interpretation of binary numerals and parser construction 1.5.1 Alternative 1: Runtime Computation Most straightforwardiy, we coud do the computation at runtime instead of compile time. For example, we might use one of the binary function implementations shown ear, or a parsing system could be designed to interpret the input grammar at runtime the first time we ask itto parse. ‘The most obvious reason to rely on a metaprogram is that by doing 2s much work as possible before the resulting program stats, Wwe get faster programs. Wen a grammar is compiled, YACC performs substantial parse table generation and optimization steps that, if done at runtime, could noticeably degrade a program's overall performance. Similarly, because binary does its work at compile tim, is values available as a compile-time constant, and the compile can encode it drecty in the abject cade, saving a ‘memory lookup when it is used. AA subiler but perhaps more important argument for using a metaprogram i thatthe result ofthe computation can interact more deeply with the target language. For example, the size of a C++ array can only be legally speced by a compile-time constant Ike binary:-value—nat by a runtime function's return value, The brace-enclosed actions in a YACC grammar can contain arbitrary CiC++ code to be executed as part ofthe generated parser. Thats only possible because the actions are processed during (gtammar compilation and passed onto the target C/C++ compiler. 1.5.2 Alternative 2: User Analysis Instead of doing computation at runtime or compile time, we could just do it by hand. Ate all's common practice to translate binary numbers to hexadecimal so that they can be used directly 2s C++ iterals, and the translation steps performed by YACC and Boost Sprit to convert the grammar description into a parser are well-known. I the atemative is writing a metaprogram that wil ony be used once, one could argue that user analysis is more convenient: It certainly is easier to translate one binary number than to wite a correct metaprogram to do so. Itonly takes a few such instances to tip the balance of convenience in the opposite direction, though. Furthermore, once the metaprogram is written, its benefits of convenience can be spread across a communi of ether programmers. Regardless of how many times i's used, a metapregram enables its user to write more expressive code, because she can speciy the result ina form that corresponds to her mental model. In a context where the values of individual bits are meaningful, it makes ‘much more sense to write binary<101010>::value than 42 or the tracitonal Ox2a. Similarly, the C source to @ handutiten parser Usually obscures the logical relationships among its grammar elements. Finally, because humans are falible, and because the logic of a metaprogram only needs tobe written once, the resulting program is more likey o be correct and maintainable. Translating binary numbers is such a mundane task tha i's easy to pay oo litle attention and get it wrong. By contrast—as anyone who's done it can attest—wriing parse tables by hand requires foo much attention, and preventing mistakes is reason enough to use a parser generator such as VAC. Le document was created by an unregistered ChmMagic, please go to http:/wm.bisente.com to register it. Thanks| 1.5.3 Why C++ Metaprogramming? Ina language such 2s C++, where the domain language is just a subset ofthe language used in the rest of the program, ‘metaprogramming is even mare powertul and convenient (© The user can enter the domain language citectl, without learning a foreign syntax or interrupting the flow of her code © Interfacing metaprograms with other code, especially other metaprograms, becomes much smoother. © No addtional build step (ike the one imposed by YACC} is require. In tradtonal programming itis very common to find oneself trying to achieve the right balance of expressiiy, correctness, and efciency. Metaprograming often allows us to interrupt that classic tension by moving the computation required for expressivily and correctness from runtime to compile tim. Top 4 This document was created by an unregistered ChmMagle, please go to hitp:/Aww.bisenter.com to register it. Thanks 1.6. When Metaprogramming? You've just seen some examples ofthe why of template metaprogramming, and you've had a tiny glimpse of thehow, but we haventt iscussed wien metaprogramming is appropriate. However, we've touched on mast ofthe relevant cftria for using template ‘metaprogramming already. As a guideline, it any three of the following conditions apply to you, a melaprogrammed solution may be appropriate. © You want the cade to be expressed in terms ofthe abstractions of the problem domain. For example, you might want a parser to be expressed by something that looks ikea formal grammar rather than as tabes full f numbers or 28 a colection of subroutines; you might want array math tobe written using operator notation on matrix and vector objects rather than as loops over sequences of numbers. © You would otherwise have to write a great deal of boilerplate implementation code. © You need to choase component implementations based on the properties oftheir type parameters © You want to take advantage of valuable properties of generic programming in C++ such as static type checking and behavioral customization, without loss of efficiency. © You want todo it all within the C++ language, without an external tool or custom source code generator. oo Top = This document was created by an unregistered ChmMagle, please go to hitp:/Aww.bisenter.com to register it. Thanks 1.7. Why a Metaprogramming Library? Rather than building up metaprograms from scratch, well be working with the high-level facilites ofthe Boost Metaprogramming Library (MPL). Even if you cid pick up this book to explore the MPL, we think youl ind your investment in learning i tobe well worthwhile because o the benefits the MPL can bring to your day-to-day work 1 Quality. Most programmers who use template metaprogramming components see them—quite properly—as implementation details to be applied toward same greater purpose. By cotrast, the MPL authors saw the job of developing useul, high-quality tools and idioms as thelr central mission, On average, the components in the Boost Metaprogramming Library are more flexible and better implemented than wat one would produce along the way to some other goal, and you can expect more optimizations and improvements inthe future as updates are released. Reuse. All libraries encapsulate code in reusable components. More importantly, a wel-designed generic brary establishes a framework of concep and idioms that provides a reusable mental mode! for approaching problems. Just as the C+4+ Standard Template Library gave us iterators and a function object protocol, the Boost Metaprogramming Library provides type iterators and a metafunction protocol. welF-considered framework o idioms focuses the ‘metaprogrammer’s design decisions and enables her to concentrate on te task at hand Portability. A good library can smooth over the ugly reales of platform ctferences. While in theory no C++ ‘metaprogram shouldbe concerned with these issues, in practice support fr templates remains inconsistent even six years after standardization. No surprises here: C++ templates are the language's furthest-reaching and most complicated feature, a fac that also accounts for the power of metapragramming in C+. Fun, Repeating the same boilerplate code over and over s tedious. Quickly assembling high-evel components into readable, elegant designs is fun! The MPL reduces boredom by eliminating the need forthe most commonly repeated ‘metaprogramming patterns. In particular, terminating specializations and explicit recursion are often easly and elegantly avoided. Productivity. Aside trom personal graificatin, the health of our projects depends on having fun programming. When we stop having un we get red, stow, and sloppy—and buggy code is even more costly than slawiy written code. [As you can see, the Boost Metaprogramming Library is motivated by the same practical considerations that underlie the evelopment of any ther brary. We think ts emergence is a sign thal template metaprogramming is finally ready to leave the realm ofthe esoteric and tind a home inthe everyday repertoire of working C++ programmers. Final, we'd tke to emphasize the foutth tem above: The MPL not only makes metaprogramming practical and easy, but its also a great pleasure to work with. We hope that youll enjoy earning about tas much as we have enjoyed using and developing it jl Top = This document was created by an unregistered ChmMagle, please go to hitp:/Aww.bisenter.com to register it. Thanks rT ad Chapter 2. Traits and Type Manipulation ope the url as of aga nt eave you we ingesson ha! mest melapogran ar athmetc nue. teens er sineea me recurring theme: metaprogramming as or rag Top = This document was created by an unregistered ChmMagle, please go to hitp:/Aww.bisenter.com to register it. Thanks 2.1. Type Associations In C+s, the entities that can be manipulated at compile time, caled metadata, are dvided roughly ito two categorestypes and antypes, Not coincidentally all he kinds of metadata can be used as template parameters. The constant integevalues used in shapter Hare among the non-types, a category that aso includes values of nearly everything else that can be known "7 time: the other integral types, enums, pointers and references to functions and “global” objects, and pointers to member "I The standard also allows templates to be passed as template parameters. If that's not mind-bending enough for you, these parameters are treated inthe standard "as types for descriptive purposes." Templates aren't types, though, and cant be passed to another template where a type is expected. Its easy to imagine doing calculations on some kinds of non-ype metadata, butt may surprise you to leam that there is also a way to do calculations with types. To get feeling for what that means—and why it matters—we'e going o look at ane ofthe simplest algorithms from the C++ standard library: ter_swap. itisiter_swap's humble duty to take two iterators and exchange the values of the objects they refer to. Itloks something Ike this: template void iter_swap(Forwardlteratort i, Forwardlterator2i2) { Timp =i; 2; lat this point youre wondering where T came from, youve got a sharp eye. Ithasnit been defined, ander_swap can't compile if we rite it that way. Informally, of course, is the type you get when the iterator is dereferenced, whats known in the C++ standard (section 24.1) as the iterators value type. Okay, but how do we name that type? Incase you already know the answer chosen by the authors of the standard library, well ask you to forget it forthe time being; we have a couple of deeper points to make. Instead, imagine we're implementing the standard library ourselves and choosing its ‘methad of handling iterators. We're going to end up wring a lot of algorithms, and many of them will ned to make an association between an iterator type and is value type. We could require al erator implementations to supply a nested type calledvalue_type, hich we'd access directly template void iter_swap(Forwardlteratort i, Forwardlterator2i2) { This document was created by an unregistered ChmMagle, please go to hitp:/Aww.bisenter.com to register it. Thanks typename 11 (see Language Note) C++ Language Note “The C++ standard requires the typename keyword witen we use adependent name 2s though it refers to a type. Forwarditeralort:value type may or may not name a type dependingon the paricularForwarditeratort thats passed. See Appendix for mare information abouttypename. Thats a perfectly good strategy for making type associations, but i's not very general. n particular, teratars in C++ are modeled on the design of pointers, withthe intention that plain pointers should themselves be valid iterators. Unfortunately, pointers can't have nested types: tha privilege is reserved for classes: void tint pt, int" p2) { ‘ter_swap(pt,p2); error: int has no member value_type’ ) 2.1.2 Taking the Long Way Around We can solve any problem by introducing an extra level of indirection. —Butler Lampson Langer es so universal programing that Anew Koen ot ling tthe Fudan! Thereof Sowae Engineering’ (FTSE). We may not be able to add a nested -:value_type to all iterators, but we can add it to a template that takes the erator ype a a parameter. ne standard rary tis temple, called era ras, ha ipl snr (2) Andrew Koenig is the co-author of Accelerated C++ and project editor for the C++ standard. For an ‘acknowledgment that does justice to his many contributions to C+ over the years, see almost any one of Bjame Stroustrup's C++ books. template stuctierator_tralts; Here's how we putt to work initer_swap: This document was created by an unregistered ChmMagle, please go to hitp:/Aww.bisenter.com to register it. Thanks template void iter_swap(Forwardlteratort i, Forwardlterator2i2) { typename HRerator_traits::value_type tm; iterator_traits is so named because it describes properties (or traits) ofits argument. n this case, the traits being described are the iterator’ five associated types: value_type, reference, pointer, diference_type, anditerator_category. ‘The most important feature of traits templates is tha they give usa way to associate information witha typenon-intusvely. In other words, i our amery cawarker Hector gives you some iteratr-ke type called hands_off that refers to anint, you can assign ita value_type without disturbing the harmony of your workgroup. All you have todo is add an explct specialization erator rats, and iter_swap wil see the tyneint when it asks about thevalue_type of Hector iterator 1For a bret review of template specialization and instantiation, see the Details section atthe end of this chapter. namespace std { template <> struct trator traits struct terator_tralts ( typedef T value_type; four more typeders Thanks tothe indirection through iteralor_traits, generic functions can now access an teator’s associated types uniformly, whether cor not it happens to be a pointe. 2.1.3 Finding a Shortcut \While specialization isa perfecty general mechanism, i's not neatly as convenient as adding nested types to classes, Le document was created by an unregistered ChmMagic, please goto http: bisenter.com to register it. Thanks Specialization comes with aot of baggage: You may have to close the namespaces youre working in and open the namespace of the tats template, and then youl have to write the text ofthe traits specialization itself. That's nota very efficient use of keystrokes: its nested typedef is the ony information that realy counts for anything Thoughtily, the standard library provides a shortcut that allows the author ofan iterator “pf the types nested inits iteralor_traits ust by writing member types inthe iterator. The primaryterator_traits template member types: reaches into the iterator to grab its 41 The C++ standard refers to ordinary template declarations and definitions—as opposed to partial or explicit (ful) speciaizations—as primary templates, template struct terator_traits ( typede! typename Iterator::value_type value_type; four more typedes, Here you can see the “extra level ofincrecton” at work: Instead of going directly to iterator: value_type, iter_swap gets there by asking terator_traits forthe iterators value_type. Unless some specialization overtdes the primariteratortraits template, ter swap sees the same value_type as it would have i it had directly accessed a nested type in the iterator. jl Top = This document was created by an unregistered ChmMagle, please go to hitp:/Awww.bisenter.com to register it. Thanks 2.2. Metafunctions lat this point you have begun to notice some similarity between tats templates and ordinary function, that's good. The parameters and nested types ofa tats template play similar roles al compile time to nction parameters and return values at runtime. The binary template trom|Chapier js certainly function-tike. If the econ | performed byiterator traits seems alle too banal to be compared to a function, though, we understand; rest assured tha things will quickly get more interesting ‘Apat rom passing and returing types instead of values, traits templates exhibit two significant features that we don't see in otdinary functions: © Specialization. We can non-ntusively alter the result of a traits template for particular “values” (pes) of parameters just by adding a specialization. We can even alter the result for a whole range of values" (e.g, all pointers) by using partial specialization. Specialization would be really strange if you could apply i to regular functions. Imagine being able to add an overload o scabs that is called only when its argument isan odd number! (© Multiple “return values.” While ordinary functions map their arguments to just one value, traits often have more than one result. For example, siditerator_ traits contains fe nested types: value_type, reference, pointe, difeence_type, anditerator category. Its not even uncommon to find traits templates that contain nested constants or static member functions. stdchar_tralts is an example of just such a component inthe standard library. Si, class templates ate enough lke functions that we can get some serious mileage out ofthe analogy. To capture the idea of ‘lass templates-as-funcions," well use the term metafunetions. Metafuncions area central abstraction of the Boost jamming Library, and formalzing them is an important key to is power. Well be discussing metafunctions in depth in hapter J but were going to cover one important ctference between metafunctions and classic tals right here as template inthe standard library all follow the “multiple return values” model. We refer to this kind of tats template as @ ici)" because is as though a handful of separate and loosely related metafunctions were mashed together into single unt. We wil avoid this idiom at all coss, because it creates major problems, First of all, there's an efficiency issue: The frst time we reach inside the teratortrats fr its value_type, the template wil be instantiated, That means a lot of things tothe compiler, but tous the important thing i that at that point the compiler has to work cut the meaning of every declaration inthe template body that happens to depend on a template parameter. In the case of iterator_traits, that means computing not only thevalue_type, but the four other associated types as well—even if we're not going to Use them. The cost of these extra type computations can realy add up as a program grows, slowing down the compilation cycle. Remember that we said type computations would get much more interesting? “More interesting’ also means more work for your compiler, and more time for you to drum your fingers on the desk waiting o see your program work, ‘Second, and more importantly, {he boi interferes with our abilty to write metafunctions that take other metafunctions as arguments. To wrap your mind around that, consider a tvial runtime function that accepts wo function arguments: template X apply f9(X x, UnaryOptf, UnaryOp2 g) { return (x); ) This document was created by an unregistered ChmMaglc, please go to http:/www.bisenter.com to register It. Thanks ‘Thats not the only way we could design apply fg though. Suppose we colapsedt anda into a single argument calledblob, as follows: template X apply f9(X x, Blob blob} { return biobfblob.g(x)); ) ‘The protocol used to calf andg here is analogous to the way you access a “rats bob": get a resul ofthe tuncton,” you reach in and access one of its members. The problem is tha there's no single way to get athe result of invoking one of these bibs. Every function lke apply_tg wll use its own set of member function names, and in order to pass rg onto another such function we might, reed to repackage itn a wrapper with new names. he beh is an ant-pattern (an isiom to be avoided), because it decreases a program’ overalinteroperabily, a he abit a its components to work smoathly together. Te orignal choice o write apply_Ig so that it accepts function arguments is a good one, because it increases inleroperabilly. When the callable arguments to apply_tg use a single protocol, we can easily exchange them: ‘include ‘oat log2ttoa): inta=apoly f9(5.01, std=:negatecfloat>(),log2); intb = apoly fo(3.141, 1oga, std::negatecfloat>(): ‘The property that allows different argument tyes to be used interchangeably is called polymorphism; eral, "the ability to take ‘matiple forms: Polymorphism In C+s, there are two kinds of polymorphism. Dynamic polymorphism allows us to handle objects of multiple ‘derived types through a single base class pointer or reference. Static polymorphism, which weve been sscussing in this chapter, allows objects of ctferent types to be manipulated in the same way merely by vitue of their support fora common syntax. The words dynamic and static indicate thatthe actual type of the objects. {determined at runtime or compile time, respectively. Dynamic polymorphism, along wit lat-bincing” or “untime. :type::value Likewise, integral constants are passed to metafunctions in similar wrappers. This extra level of indirection might seem inconvenient, but by now you can probably guess the reason fori Requiring al metafunctons to accept and retum types makes them more uniform, more upon ‘and more interoperable. Youll see lots of examples of how this application ofthe FTSE pays olin the next few chapters! 5] You may have noticed that the metafunction protocol seems to prevent us from achieving the very goal that was our reason for making metatunctions polymorphic: we wanted tobe able to write metafunctions that take other metafunctions as arguments. Since metafunctons are templates, not types, we can't pass them were types are expected. For now we'l just ave ta ask you to suspend your disbele for the rest ofthis chapter; we promise to deal with that issue in Bhapter All those benef aside, wring :type:-value whenever you want to compute an actual integral constantdoes grow somewhat tedious. Purely as a convenience, a numerical metafunction author may decide to provide an identical nested :value direct in the ‘metafunction itselt. All ofthe numerical metatunctions from the Boost library we cover inthis book do just that. Note that although its ‘kay to take advantage of value when you know its supplied by the metafunction you're caling, you cat count on a nestedvalue in general, even when you know the metafunction yields a numerical resut. Top 4 This document was created by an unregistered ChmMagle, please go to hitp:/Awww.bisenter.com to register it. Thanks 2.4. Making Choices at Compile Time lt this point you stl find yourself litle nonplussed atthe idea of type computations, we can hardy blame you. Admittedly, using @ ‘metafunction to find the value_type ofan trator nat much more than a kindof glorified table lockup. If ths idea of "computation with types" fs going to have legs, there's got to be more tt than making type association. 2.4.1 More iter_swap To see how we can put metafuncions to use in eal code, let's go back to playing “C++ stander library implementor.” Sorry to say it but by now wel pases oe ‘of bug reports trom our performance-minded customers, complaining that the way we defined iter_swap infection 2.1.4is horiblyinefcent fr some terators. Apparently one guy tried passing inte iterators of sldiilstestd:vectorestdstring> >, which iterate overvectors of stings and his protler told him thaiter_swap was the performance bottleneck, Inhindsight, t's hard to be very surprised: The first statement in iter_swap makes a copy of the value referenced by ane ofthe iterators. Since copying a vector means copying ala is elements, and each string element copied or assigned is likely to require a {dynamic memory allocation and bitwise copy of the strng's characters, this starts to look pretty bad for performance. Fortunately there's a workaround. Because the standard library provides an efficient version of swap for vectors that just exchanges 2 few intemal pointers, we can tell our customer to simply dereference the iterators and call swap on the results std:swap(it, “2: That response isnt very satistyng, though. Why shouldnt iter_swap be equally efficient? In a flash of inspiration, we remember the fundamental theorem of software engineering: Cant we just add a level of indirection and delegate the responsibily for efciency to swap? template void iter_swap(Forwardlteratort i, Forwardlterator2i2) { stdswap(‘it 2) ) ‘That looks good, but running our test suite shows that calingswap doesrit always work. Did you notice thatter_swap will accept two iterators ofciferent types? It seems one ofthe tess tres to excange the value pointed to by an nt with the one pointed to by a long using ter_swap. The swap function, however, ony operates on two objects of thesametype: template void swap\T& x, T& y This document was created by an unregistered ChmMagic, please goto http:s/wmw.bisenter.com to register it. Thanks ‘The implementation ofiter_swap above causes a compilation error when we ty to use it orn” and long’, because nostd'swap overload matches the argument types (int, ong) \We could try to solve this problem by leaving the slow implementation ofitr_swap in place, and adding an overload 1 Generalized (slow) version template void iter_swap(Forwardlteratort i, Forwardlterator2i2) { typename iterator trats:value_type tmp =i; 1; 11 Abetter match when the two iterators are the same type template void iter_swap(Forwardlterator it, Forwardterator 2) { sld:swap("it, “2; 1! sometimes faster ) ‘The C++ rules for partial ordering of function templates say thatthe new overioad isa better match, when i matches. That handles the problem for int" andlong" and passes the testsuite. We ship it 2.4.2 A Fly in the Ointment Pretty soon, though, someone will notice that we're stil missing an important opportunity for optimization. Consider what happens winen we call iter_swap on the iterators ofst:vectorestd:string> and stcsstestdstring>. The to iterators will have the same value_type—with is own etficentswap—but since the iterators themselves are different types, the fasfter_ swap overioad that uses itwont be called. Whats needed here is a way to getter swap to work on two diferent iterator types that share a singlevalue type. Since we're playing ‘standard library mplementor,” we can always try rewriting swap soit works on two diffrent types: template void swap(T1& a, T28 b) { Thi sb: b=tmp; This simple fx wil handle most ofthe cases our users encounter. This document was created by an unregistered ChmMagle, please go to hitp:/Awww.bisenter.com to register it. Thanks 2.4.3 Another Fly! Unfortunately, there's a category of teators for which this stilwon't work: these whaseoperator* yields aproxy reference. A proxy reference isnt, in fac, a reference at al, uta class that ties to emulate one: For an iterator that's both readable and writable, a roxy reference is usta class that is both convertible to, and assignable trom, the value_type. Thebestinom sang of sch an erator tat of verbo ET corse hat srs each ois seers ina sgl Since there's no such thing as a real reference to abit a proxy is used so the vecor behaves almost exact lke any other vector. The proxy’ operator=(bo0) writs into the appropiate bit ofthe vector, and itmperalor bool) retums TAuei and oniy if that itis setin the vector, someting like {61 The problem might easily have been missed by our regression tests; some people aren't even convinced vector:iterator is a valid iterator. The subject of howvectorcboos and its iterators ft int the standarc ct of much debate, He en wrote two papers forthe C++ standards commitiee ((exte5]far2r4), and a Guru of ne weetforwS0] about tne problems. Work has begun inthe commites ona system of new iterator concepts that, we hope, will hep to resolve the issues. struct proxy { proxyé operator=(bool x) i it byteslpos8 [= (1u << (p0s%8)); else bytes[pos8] &= ~(1u << (poste); retum “ths; ) ‘operator bool) const i retum bytes{posi8] & (1u << (post); ) unsigned char* bytes; size_tpos: struct bit terator { typedet bool value_type; typedet proxy reference; ‘more typedets. proxy operator‘) const; ‘more operations. Now consider what happens when iter_swap dereferences abit trator and tries to pass a couple of proxy relerences off to std'swap. Recall that sinceswap modes its arguments, they are passed by non-const reference. The problem s thal the proxies retumed by operator* are temporares, andthe compiler willissue an error when we ty to pass temporaries as non-const reference ‘arguments. Most of the time thats the right decision, because any changes we made tothe temporaties would just disappear into the ether. The original implementation of iter_swap, though, works fine on the iterators of vector. This document was created by an unregistered ChmMagle, please go to hitp:/Aww.bisenter.com to register it. Thanks 2.4.4 The Flyswapper What's needed, finally, isa way to pick the “ast” implementation of iter_swap only when the iterators have the samevalue_type and their reference types are real references, not proxies. To make these choices, we need some way to ask (and answer!) the questions "Is Ta real reference?” and "Are these twavalue_types the same?" Boost contains an entre brary of metatunctions designed to query and manipulate fundamental tats ike type identity and "relerence-ness.” Given the appropriate type traits, we can decide whether to use swap or do the swapping ourselves: include include include (/forlerator_tralts include eutlity> for swap template void iter_swap(Forwardlteratort i, Forwardlterator2i2) { ‘ypedet iterator_tralts traits: ‘ypedet typename tratst:value type vi ‘ypedet typename tats :reterence rt ‘ypedet iterator tralts tralts2; ‘ypedet typename trats2:value_type v2 ‘ypedet typename trats2:reterence 12; bool const use_swap = boost:Is_samecv'.v2>:,value 88 boost:is_refereneecrt>:value 88 boost:s_reference:,value; \We havent closed the final brace onite_swap, but at this point ll we have to dois find a way to pick ferent behaviors based on the value of use_swap. There are actualy/ts of ways to approach that problem, many of which well cover Weve cleverly anticipated the need for cispatching by forward-declaringiter_swap_impiLA We can provide the two behaviors in specializations of ier_swap_mpl outside the body ofiter_swap): 1 tle unnatural foresight isthe authors’ prerogative! template <> struct iter_swap_Implctrue> J the ast’ one { template static void do_iForwardlteratort it, Forwarlterator2 2) t sté:swap(it, 2) ) I Le document was created by an unregistered ChmMagic, please go to http:/wm.bisente.com to register it. Thanks| template <> struct iter_swap_Implcfalse> i/the one that always works { template static void do_iForwardlteratort it, Forwarlterator2 2) ( ‘ypename ierator_tralts:value type tmp =“ Now ter swap_impl :do_it provides an appropriate implementation ofiter_swap for ether possible value ofuse_swap. Because do_itisa static member function, ter_swap can calit without constructing an instance oiter_swap_impi iter_swap_impleuse_swap>:do_iti,"2); Now we can close the brave and breathe a sigh of relief while our regression tests all pass. We ship! There is much rejoicing! Our customers have an iter_swap that is both fastand correct. a | Top = This document was created by an unregistered ChmMagle, please go to hitp:/Aww.bisenter.com to register it. Thanks This document was created by an unregistered ChmMagle, please go to hitp:/Aww.bisenter.com to register it. Thanks 2.5. A Brief Tour of the Boost Type Traits Library tus ct tal ost eerste mtg ends peda as ke se vey fe ot Ty a has pen oa ates een estes tsa conmitee’s rt Terncal Rep ad] hunger of ig cone n ees te Teste tats decoy your bos ston 28 the documentation inthe 2.5.1 General ‘There area few things you need to knaw about the library asa whole: First, as you may have guessed trom theiter_swap example, allo the library's metafunctions are in namespace boost, and there's @ simple convention forinclude-ng the header that defines any of them include ‘Second, 28 we implied earlier all of Boost’s numerical metafunctions, as a convenience, provide a nested value crectly in the ‘metafunction. t may be abit strange to think of boo-valued metafunctons ke is_reference as “numerical but C++ classiiesbool as ‘an integral ype and the same convention apples to al ntegral-valued metafunctons. Third, there area few type traits (eg. has_ttvial destructor) that require non-standard compiler support in order to be fully functional. A few compilers, notably Metrowerks CodeWarrior and SGI MipsPro, have actually implemented the necessary primitives. On other compilers, these traits generally are correct for some types and degrade "gracefully and safely" for others. By ‘gracefully’ we mean that even wien the traits don have the corect result, thelr use wil still compile, To understand what we mean by “safely,” you have to know that these tals are mostly used to decide whether certain optimizations are possible. For example, the storage fora type witha trivial destructor may be reused without destroying the object, itcontans. I, however, you cant determine tha the type has a tvial destructor, you must destroy the object before reusing its storage. When has_trvial_destructor can't determine the correct result value, it retumalse so that generic code will aways take the safe route and invoke T's destructor. Last, be aware that type categorization metafunctons lke is_enum, which we describe next, generally ignoreev-qualfcation (const andvolaile), so thatis_enumeT const» alvays has the same result ads_enumeT>. Each ofthe folowing subsections describes a diferent group of traits. 2.5.2 Primary Type Categorization ‘These unary melatunctions determine which ofthe fundamental ype categories descrived in the C++ standard applies to their argument. For any given type T, one and only one ofthese metafunctions should yield ave result, [Nine traits cover the type categories that most people are familar with. There's not much to say aboutis.voideT>,Is_pointer, is referencecT>,is_array, andis_enumeT>; they do just what youd expect.is_inlegraleT> identfies char, bool, and all the Varieties of signed and unsignedinteger types. Similar i. loatcT> identifies the floating-point typestoat, double, andlong double. This document was created by an unregistered ChmMagic, please goto hitp:/ww.bisente.com to register it. Thanks Unoturaty,wioucomie suport rionc> says eure, si oascT> ste forth asses and ron '®l Classes may be declared using thestruct keyword, but they are stil classes according to the C++ standard. In fact, the folowing two dectarations ar interchangeable: class X; struct X;/ declares the same X structis only distinguished from cass in definitions, where struct causes bases and members to bepublc by setaut. ‘There are two mare categories that most programmers encounter less offen. Pointers to member functions, which have the fom (C= args.) ov and pointers to data members, written as box ate identified by is_member_pointer. Note thatis_pointer doesn’ identiy these types, even though they'e called pointers. Lastly, s_function identifies function types ofthe form Rlargs..) Many people never see an unadorned function type, because ofthe way function names, when nat immediately invoked, ‘automatically become function pointers of references of the form RC) (args..) or (8) args.) [fable 2. ists the primary type tats. This document was created by an unregistered ChmMagic, please goto http:s/wmw.bisenter.com to register it. Thanks Table 2.1. Primary Type Categorization Primary Trait sstype:wvalue and ::value is arayeT> ‘tue iT is an aray type is elasseT> “TRueiff isa cass type; without comple support, may aso reportTRue or is enumet> ‘tu iT i an enumeration ype. is Hoatet> ‘TAueiftT isa fating-point ype. is funcionet> ‘tu iT sa function type is integraleT> ‘tue iT is an integral ype. |s_member_pointer “TR ifs a pointer to function or data member. 's_pointer “TRueitT is a pointer type (but not a pointer to member) Is relerencecT> true fT isa reterence type. 's_unioneT> “TRue if i a union; without compiler support, always reportalse. Is voideT> ‘tue if is ofthe form evvoid. 2.5.3 Secondary Type Categorization The traits in fable 2Jrepresent useful groupings of, o distinctions within, the primary categories. This document was created by an unregistered ChmMagic, please goto http:s/wmw.bisenter.com to register it. Thanks Table 2.2. Secondary Type Categorization ‘Secondary Trait 's_arithmeticet> 's_integraleT>:value || Is MoateT>::value is_compound lis fundamentaleT>:value 's fundamentaleT> 's_arithmeticeT>:,value || Is voideT>:value |s_member function pointer true if Ts a pointer to member function, 's_objecteT> is funetioncT>:value | Is reterencecT>:value Is voideT>:value) Is scalareT> 's_arithmeticeT>:value i 's_enumeT>:,valve | 's_pointer::value |s_member_pointer:value 2.5.4 Type Properties ‘The type trails brary uses the term properties as a kindof catch-all term for traits other than those directly related tothe standard ‘ype categories. The simplest trait in thi croup areis_const andis_volatl, which detec their arguments’ cv-quallication. The rest [Fables 2and of the type properties are summarized in Table 2.3. Type Properties Type Property per: alignment of ‘A postive multiple of T's memory alignment requirements (the ibrary tries to minimize that multiple. is_emply ‘tue if the compiler optimizes away space for empty base classes and is an emply class, |s_polmarphiceT> ‘TRuelitT i a class with at east one virtual member uncon, This document was created by an unregistered ChmMagic, please goto http:s/wmw.bisenter.com to register it. Thanks Table 2.4. More Type Properties mh Coenen a — swore oo el PI POD stands for “plain old data.” Believe itor not, that's a technical term in the C++ standard. The standard ives us license to make all kinds of special assumptions about POD types. For example, PODs always ‘occupy contiguous bytes of storage; other types might not. A POD type is defined to be either a scalar, an array of PODS, ora struct or union that has no user-declared constructors, no user-declared copy assignment, no user-declared destructor, no private or protected non-stalic data members, no base classes, ro non-static data members of non-POD, reference, or painter to member type, or array of such types, and ro virtual functions. ‘The traits in [able 2.dare most usetul for selecting optimizations. With compiler support they can be implemented more accurately allowing only io be replaced by if an only ii inthe table. 2.5.5 Relationships Between Types ‘The library contains three important metatunctions that indicate relationships between types. We've already seenis_samecT,U>, whose value(s tre when andU are identical types.is_convertble yields rue if and only it an object of typeT can be Implicity converted to type U. Finally i_base_and_derived:-value is TRueit and only ifBis a base class ofD. 2.5.6 Type Transformations ‘The metafunctions isted in[fable 2.9 pertorm fundamental type manipulations. Note that unlike other type tats metaunctions weve iscussed co far, members ofthis group yield type results rather than Boolean values. You can think of them as being operators in the “arithmetic of types. Le document was created by an unregistered ChmMagic, please go to http:/wm.bisente.com to register it. Thanks| Table 2.5. Transformations Types Transformation type remove_consteT> T without any top-levelconst. For example, const int becomes int, butconstnt* remains unchanged. remove_volatilecT> T without any top-levelvolatile, Fr example, volatile intbecomes int. remove cv T without any top-level cv-qualifrs. For example.const volatile intbecomesint. remove_referenoe T without any top-level reference. For example int& becomes nt but in” remains unchanged. remove_bounds T without any top-level array brackets. For examplejnt2I{3] becomes int remove_pointer T without any top-level pointer. For example it* becomes int, butint& remains unchanged. add_reterence Tis a reference type, thenT, otherwise T&. ‘add_pointer remove_reference:type". For example. int andint& both becomeint”. ‘add_consteT> T const ‘add_volatlecT> T volatile ‘add_cveT> T const volatile A this point you might be wondering why we bothered withthe last three transformations inthe table, After all,adé_const:type is just a more verbose way to write T const. I tuns out tat is important to be abe to express even te simples transformations in ‘metafunction form so they can be passed on to other metafunctons (which, as promised, well show you how todo in the next chapter) PR rad Top = This document was created by an unregistered ChmMagle, please go to hitp:/Aww.bisenter.com to register it. Thanks 2.6. Nullary Metafunctions Probably the most important ting weve done in tis chapter has been to describe the {netatunciorf concept, but there's one {question we sill haven't answered: What does a nullary (zero-argument) metafuncton look ke? From the requirements standpoint, @nullary metafunction is any type, whether i's a plain class ora cass template specialization, that provides us with a nested type member. For instance, add_constcint> i anullary metafuncton that always returns the same result it const. ‘The easiest way to wntea nuilary metafuncton isto go with a simplestruct struct alvays_int { typedet int ype, I oo Top = This document was created by an unregistered ChmMagle, please go to hitp:/Aww.bisenter.com to register it. Thanks 2.7. Metafunction Definition Finally, we have everything we need to write @ complete, formal description of metatunctons ad Definition Ametafunctions either © a cass template allot whose parameters are types © actass with a publicly accessible nested result ype calledype. fod Top = This document was created by an unregistered ChmMagle, please go to hitp:/Awww.bisenter.com to register it. Thanks 2.8. History ‘The Boost Type Trats brary was inspired by a component in SGI's STL implementation that looked something like this: struct tre type (); struct false_type ( template struct type_traits i! assume nothing { typede' false_type has_tivial defaut_ constructor; ‘ypedet false_type has_tivial copy constructor; typede' false_type has_tvial_assignment_operator typedet false_type has trivial destructor; ‘typed flse_ype is_POD_type: iF templates struct type_tralts I! specialization for char { typede true_type has_trvial default constructor; ‘ypedet true_type has_trval_copy constructor; typedel true_type has_trval_assignment_ operator; typedet true type has_trvial destructor: typedet true_typeis_ POD_type: ‘more specializations follow. Its interesting to note that athough the SGI type traits yielded result types, it's stil a loE|“wrich kils polymorphism, The SGI Cesigners must have had other reasons fr using nested types instead of bool constants "91 Fora clue as to one possible reason, sedpection 9.2 Boost. Type Tuaits was the fist C++ ibrar that explicitly recognized the importance of using single-valued metafunctions. Boost rejected the ‘bit desion primarly because it would reserve a very general namelype rats ora single template. The name seemed to demand that any new traits be assimilated there—a Borg blab! Anyone wo wanted to write a similar component would have felt compelled to go in and modify this one template, potentially causing bugs. At the time, the positve impact tis choice would have on efficiency and interoperability wasn't well understood, ‘The designers established a convention that traits witha Boolean result would have a :value and those wih a type result would have a type, so users didnt have to guess at how to invoke a given trait. That choice indicates that they recognized the value of polymorphism, even i they didnt reach the ulimate conclusion that all metafunctions should supply a:type, ‘As a matter of fac, the type tals werer't seen as fnetafunctiong} until work on the Boost Metaprogramming Library (MPL) was begun. At that pont, the convention used in the Type Tras brary became the basis forthe uiferm protocol used by MPL metafunctions, and Boost Type Traits library was updated accordingly

Você também pode gostar