C++ S The Guide Addison Wesley (2017)

C%2B%2B%20s_%20The%20%20Guide-Addison-Wesley%20(2017)

C%2B%2B%20s_%20The%20%20Guide-Addison-Wesley%20(2017)

C%2B%2B%20s_%20The%20%20Guide-Addison-Wesley%20(2017)

User Manual: Pdf

Open the PDF directly: View PDF PDF.
Page Count: 2543

DownloadC++ S The  Guide Guide-Addison-Wesley (2017)
Open PDF In BrowserView PDF
C++ Templates
The Complete Guide
Second Edition

David Vandevoorde
Nicolai M. Josuttis Douglas Gregor

Boston • Columbus • Indianapolis • New York • San Francisco • Amsterdam •
Cape Town Dubai • London • Madrid • Milan • Munich • Paris • Montreal •
Toronto • Delhi • Mexico City São Paulo • Sydney • Hong Kong • Seoul •
Singapore • Taipei • Tokyo

Many of the designations used by manufacturers and sellers to distinguish their
products are claimed as trademarks. Where those designations appear in this
book, and the publisher was aware of a trademark claim, the designations have
been printed with initial capital letters or in all capitals.
The authors and publisher have taken care in the preparation of this book, but
make no expressed or implied warranty of any kind and assume no responsibility
for errors or omissions. No liability is assumed for incidental or consequential
damages in connection with or arising out of the use of the information or
programs contained herein.
For information about buying this title in bulk quantities, or for special sales
opportunities (which may include electronic versions; custom cover designs; and
content particular to your business, training goals, marketing focus, or branding
interests), please contact our corporate sales department at
corpsales@pearsoned.com or (800) 382-3419.
For government sales inquiries, please contact
governmentsales@pearsoned.com.
For questions about sales outside the U.S., please contact
intlcs@pearson.com.
Visit us on the Web: informit.com/aw
Library of Congress Catalog Number: 2017946531
Copyright © 2018 Pearson Education, Inc.
This book was typeset by Nicolai M. Josuttis using the LATEX document
processing system. All rights reserved. Printed in the United States of America.
This publication is protected by copyright, and permission must be obtained
from the publisher prior to any prohibited reproduction, storage in a retrieval
system, or transmission in any form or by any means, electronic, mechanical,
photocopying, recording, or likewise. For information regarding permissions,
request forms and the appropriate contacts within the Pearson Education Global
Rights & Permissions Department, please visit
www.pearsoned.com/permissions/.
ISBN-13: 978-0-321-71412-1
ISBN-10: 0-321-71412-1

1 17

To Alessandra & Cassandra
—David
To those who care for people and mankind
—Nico
To Amy, Tessa & Molly
—Doug

Contents
Preface
Acknowledgments for the Second Edition
Acknowledgments for the First Edition
About This Book
What You Should Know Before Reading This Book
Overall Structure of the Book
How to Read This Book
Some Remarks About Programming Style
The C++11, C++14, and C++17 Standards
Example Code and Additional Information
Feedback
Part I: The Basics
1 Function Templates
1.1 A First Look at Function Templates
1.1.1 Defining the Template
1.1.2 Using the Template
1.1.3 Two-Phase Translation
1.2 Template Argument Deduction
1.3 Multiple Template Parameters
1.3.1 Template Parameters for Return Types
1.3.2 Deducing the Return Type
1.3.3 Return Type as Common Type
1.4 Default Template Arguments
1.5 Overloading Function Templates

1.6 But, Shouldn’t We …?
1.6.1 Pass by Value or by Reference?
1.6.2 Why Not inline?
1.6.3 Why Not constexpr?
1.7 Summary
2 Class Templates
2.1 Implementation of Class Template Stack
2.1.1 Declaration of Class Templates
2.1.2 Implementation of Member Functions
2.2 Use of Class Template Stack
2.3 Partial Usage of Class Templates
2.3.1 Concepts
2.4 Friends
2.5 Specializations of Class Templates
2.6 Partial Specialization
2.7 Default Class Template Arguments
2.8 Type Aliases
2.9 Class Template Argument Deduction
2.10 Templatized Aggregates
2.11 Summary
3 Nontype Template Parameters
3.1 Nontype Class Template Parameters
3.2 Nontype Function Template Parameters
3.3 Restrictions for Nontype Template Parameters
3.4 Template Parameter Type auto
3.5 Summary
4 Variadic Templates
4.1 Variadic Templates
4.1.1 Variadic Templates by Example
4.1.2 Overloading Variadic and Nonvariadic Templates
4.1.3 Operator sizeof…
4.2 Fold Expressions
4.3 Application of Variadic Templates

4.4 Variadic Class Templates and Variadic Expressions
4.4.1 Variadic Expressions
4.4.2 Variadic Indices
4.4.3 Variadic Class Templates
4.4.4 Variadic Deduction Guides
4.4.5 Variadic Base Classes and using
4.5 Summary
5 Tricky Basics
5.1 Keyword typename
5.2 Zero Initialization
5.3 Using this->
5.4 Templates for Raw Arrays and String Literals
5.5 Member Templates
5.5.1 The .template Construct
5.5.2 Generic Lambdas and Member Templates
5.6 Variable Templates
5.7 Template Template Parameters
5.8 Summary
6 Move Semantics and enable_if<>
6.1 Perfect Forwarding
6.2 Special Member Function Templates
6.3 Disable Templates with enable_if<>
6.4 Using enable_if<>
6.5 Using Concepts to Simplify enable_if<> Expressions
6.6 Summary
7 By Value or by Reference?
7.1 Passing by Value
7.2 Passing by Reference
7.2.1 Passing by Constant Reference
7.2.2 Passing by Nonconstant Reference
7.2.3 Passing by Forwarding Reference
7.3 Using std::ref() and std::cref()
7.4 Dealing with String Literals and Raw Arrays

7.4.1 Special Implementations for String Literals and Raw Arrays
7.5 Dealing with Return Values
7.6 Recommended Template Parameter Declarations
7.7 Summary
8 Compile-Time Programming
8.1 Template Metaprogramming
8.2 Computing with constexpr
8.3 Execution Path Selection with Partial Specialization
8.4 SFINAE (Substitution Failure Is Not An Error)
8.4.1 Expression SFINAE with decltype
8.5 Compile-Time if
8.6 Summary
9 Using Templates in Practice
9.1 The Inclusion Model
9.1.1 Linker Errors
9.1.2 Templates in Header Files
9.2 Templates and inline
9.3 Precompiled Headers
9.4 Decoding the Error Novel
9.5 Afternotes
9.6 Summary
10 Basic Template Terminology
10.1 “Class Template” or “Template Class”?
10.2 Substitution, Instantiation, and Specialization
10.3 Declarations versus Definitions
10.3.1 Complete versus Incomplete Types
10.4 The One-Definition Rule
10.5 Template Arguments versus Template Parameters
10.6 Summary
11 Generic Libraries
11.1 Callables
11.1.1 Supporting Function Objects

11.1.2 Dealing with Member Functions and Additional Arguments
11.1.3 Wrapping Function Calls
11.2 Other Utilities to Implement Generic Libraries
11.2.1 Type Traits
11.2.2 std::addressof()
11.2.3 std::declval()
11.3 Perfect Forwarding Temporaries
11.4 References as Template Parameters
11.5 Defer Evaluations
11.6 Things to Consider When Writing Generic Libraries
11.7 Summary
Part II: Templates in Depth
12 Fundamentals in Depth
12.1 Parameterized Declarations
12.1.1 Virtual Member Functions
12.1.2 Linkage of Templates
12.1.3 Primary Templates
12.2 Template Parameters
12.2.1 Type Parameters
12.2.2 Nontype Parameters
12.2.3 Template Template Parameters
12.2.4 Template Parameter Packs
12.2.5 Default Template Arguments
12.3 Template Arguments
12.3.1 Function Template Arguments
12.3.2 Type Arguments
12.3.3 Nontype Arguments
12.3.4 Template Template Arguments
12.3.5 Equivalence
12.4 Variadic Templates
12.4.1 Pack Expansions
12.4.2 Where Can Pack Expansions Occur?
12.4.3 Function Parameter Packs

12.4.4 Multiple and Nested Pack Expansions
12.4.5 Zero-Length Pack Expansions
12.4.6 Fold Expressions
12.5 Friends
12.5.1 Friend Classes of Class Templates
12.5.2 Friend Functions of Class Templates
12.5.3 Friend Templates
12.6 Afternotes
13 Names in Templates
13.1 Name Taxonomy
13.2 Looking Up Names
13.2.1 Argument-Dependent Lookup
13.2.2 Argument-Dependent Lookup of Friend Declarations
13.2.3 Injected Class Names
13.2.4 Current Instantiations
13.3 Parsing Templates
13.3.1 Context Sensitivity in Nontemplates
13.3.2 Dependent Names of Types
13.3.3 Dependent Names of Templates
13.3.4 Dependent Names in Using Declarations
13.3.5 ADL and Explicit Template Arguments
13.3.6 Dependent Expressions
13.3.7 Compiler Errors
13.4 Inheritance and Class Templates
13.4.1 Nondependent Base Classes
13.4.2 Dependent Base Classes
13.5 Afternotes
14 Instantiation
14.1 On-Demand Instantiation
14.2 Lazy Instantiation
14.2.1 Partial and Full Instantiation
14.2.2 Instantiated Components
14.3 The C++ Instantiation Model
14.3.1 Two-Phase Lookup

14.3.2 Points of Instantiation
14.3.3 The Inclusion Model
14.4 Implementation Schemes
14.4.1 Greedy Instantiation
14.4.2 Queried Instantiation
14.4.3 Iterated Instantiation
14.5 Explicit Instantiation
14.5.1 Manual Instantiation
14.5.2 Explicit Instantiation Declarations
14.6 Compile-Time if Statements
14.7 In the Standard Library
14.8 Afternotes
15 Template Argument Deduction
15.1 The Deduction Process
15.2 Deduced Contexts
15.3 Special Deduction Situations
15.4 Initializer Lists
15.5 Parameter Packs
15.5.1 Literal Operator Templates
15.6 Rvalue References
15.6.1 Reference Collapsing Rules
15.6.2 Forwarding References
15.6.3 Perfect Forwarding
15.6.4 Deduction Surprises
15.7 SFINAE (Substitution Failure Is Not An Error)
15.7.1 Immediate Context
15.8 Limitations of Deduction
15.8.1 Allowable Argument Conversions
15.8.2 Class Template Arguments
15.8.3 Default Call Arguments
15.8.4 Exception Specifications
15.9 Explicit Function Template Arguments
15.10 Deduction from Initializers and Expressions
15.10.1 The auto Type Specifier
15.10.2 Expressing the Type of an Expression with decltype

15.10.3 decltype(auto)
15.10.4 Special Situations for auto Deduction
15.10.5 Structured Bindings
15.10.6 Generic Lambdas
15.11 Alias Templates
15.12 Class Template Argument Deduction
15.12.1 Deduction Guides
15.12.2 Implicit Deduction Guides
15.12.3 Other Subtleties
15.13 Afternotes
16 Specialization and Overloading
16.1 When “Generic Code” Doesn’t Quite Cut It
16.1.1 Transparent Customization
16.1.2 Semantic Transparency
16.2 Overloading Function Templates
16.2.1 Signatures
16.2.2 Partial Ordering of Overloaded Function Templates
16.2.3 Formal Ordering Rules
16.2.4 Templates and Nontemplates
16.2.5 Variadic Function Templates
16.3 Explicit Specialization
16.3.1 Full Class Template Specialization
16.3.2 Full Function Template Specialization
16.3.3 Full Variable Template Specialization
16.3.4 Full Member Specialization
16.4 Partial Class Template Specialization
16.5 Partial Variable Template Specialization
16.6 Afternotes
17 Future Directions
17.1 Relaxed typename Rules
17.2 Generalized Nontype Template Parameters
17.3 Partial Specialization of Function Templates
17.4 Named Template Arguments
17.5 Overloaded Class Templates

17.6 Deduction for Nonfinal Pack Expansions
17.7 Regularization of void
17.8 Type Checking for Templates
17.9 Reflective Metaprogramming
17.10 Pack Facilities
17.11 Modules
Part III: Templates and Design
18 The Polymorphic Power of Templates
18.1 Dynamic Polymorphism
18.2 Static Polymorphism
18.3 Dynamic versus Static Polymorphism
18.4 Using Concepts
18.5 New Forms of Design Patterns
18.6 Generic Programming
18.7 Afternotes
19 Implementing Traits
19.1 An Example: Accumulating a Sequence
19.1.1 Fixed Traits
19.1.2 Value Traits
19.1.3 Parameterized Traits
19.2 Traits versus Policies and Policy Classes
19.2.1 Traits and Policies: What’s the Difference?
19.2.2 Member Templates versus Template Template Parameters
19.2.3 Combining Multiple Policies and/or Traits
19.2.4 Accumulation with General Iterators
19.3 Type Functions
19.3.1 Element Types
19.3.2 Transformation Traits
19.3.3 Predicate Traits
19.3.4 Result Type Traits
19.4 SFINAE-Based Traits
19.4.1 SFINAE Out Function Overloads

19.4.2 SFINAE Out Partial Specializations
19.4.3 Using Generic Lambdas for SFINAE
19.4.4 SFINAE-Friendly Traits
19.5 IsConvertibleT
19.6 Detecting Members
19.6.1 Detecting Member Types
19.6.2 Detecting Arbitrary Member Types
19.6.3 Detecting Nontype Members
19.6.4 Using Generic Lambdas to Detect Members
19.7 Other Traits Techniques
19.7.1 If-Then-Else
19.7.2 Detecting Nonthrowing Operations
19.7.3 Traits Convenience
19.8 Type Classification
19.8.1 Determining Fundamental Types
19.8.2 Determining Compound Types
19.8.3 Identifying Function Types
19.8.4 Determining Class Types
19.8.5 Determining Enumeration Types
19.9 Policy Traits
19.9.1 Read-Only Parameter Types
19.10 In the Standard Library
19.11 Afternotes
20 Overloading on Type Properties
20.1 Algorithm Specialization
20.2 Tag Dispatching
20.3 Enabling/Disabling Function Templates
20.3.1 Providing Multiple Specializations
20.3.2 Where Does the EnableIf Go?
20.3.3 Compile-Time if
20.3.4 Concepts
20.4 Class Specialization
20.4.1 Enabling/Disabling Class Templates
20.4.2 Tag Dispatching for Class Templates
20.5 Instantiation-Safe Templates

20.6 In the Standard Library
20.7 Afternotes
21 Templates and Inheritance
21.1 The Empty Base Class Optimization (EBCO)
21.1.1 Layout Principles
21.1.2 Members as Base Classes
21.2 The Curiously Recurring Template Pattern (CRTP)
21.2.1 The Barton-Nackman Trick
21.2.2 Operator Implementations
21.2.3 Facades
21.3 Mixins
21.3.1 Curious Mixins
21.3.2 Parameterized Virtuality
21.4 Named Template Arguments
21.5 Afternotes
22 Bridging Static and Dynamic Polymorphism
22.1 Function Objects, Pointers, and std::function<>
22.2 Generalized Function Pointers
22.3 Bridge Interface
22.4 Type Erasure
22.5 Optional Bridging
22.6 Performance Considerations
22.7 Afternotes
23 Metaprogramming
23.1 The State of Modern C++ Metaprogramming
23.1.1 Value Metaprogramming
23.1.2 Type Metaprogramming
23.1.3 Hybrid Metaprogramming
23.1.4 Hybrid Metaprogramming for Unit Types
23.2 The Dimensions of Reflective Metaprogramming
23.3 The Cost of Recursive Instantiation
23.3.1 Tracking All Instantiations
23.4 Computational Completeness

23.5 Recursive Instantiation versus Recursive Template Arguments
23.6 Enumeration Values versus Static Constants
23.7 Afternotes
24 Typelists
24.1 Anatomy of a Typelist
24.2 Typelist Algorithms
24.2.1 Indexing
24.2.2 Finding the Best Match
24.2.3 Appending to a Typelist
24.2.4 Reversing a Typelist
24.2.5 Transforming a Typelist
24.2.6 Accumulating Typelists
24.2.7 Insertion Sort
24.3 Nontype Typelists
24.3.1 Deducible Nontype Parameters
24.4 Optimizing Algorithms with Pack Expansions
24.5 Cons-style Typelists
24.6 Afternotes
25 Tuples
25.1 Basic Tuple Design
25.1.1 Storage
25.1.2 Construction
25.2 Basic Tuple Operations
25.2.1 Comparison
25.2.2 Output
25.3 Tuple Algorithms
25.3.1 Tuples as Typelists
25.3.2 Adding to and Removing from a Tuple
25.3.3 Reversing a Tuple
25.3.4 Index Lists
25.3.5 Reversal with Index Lists
25.3.6 Shuffle and Select
25.4 Expanding Tuples
25.5 Optimizing Tuple

25.5.1 Tuples and the EBCO
25.5.2 Constant-time get()
25.6 Tuple Subscript
25.7 Afternotes
26 Discriminated Unions
26.1 Storage
26.2 Design
26.3 Value Query and Extraction
26.4 Element Initialization, Assignment and Destruction
26.4.1 Initialization
26.4.2 Destruction
26.4.3 Assignment
26.5 Visitors
26.5.1 Visit Result Type
26.5.2 Common Result Type
26.6 Variant Initialization and Assignment
26.7 Afternotes
27 Expression Templates
27.1 Temporaries and Split Loops
27.2 Encoding Expressions in Template Arguments
27.2.1 Operands of the Expression Templates
27.2.2 The Array Type
27.2.3 The Operators
27.2.4 Review
27.2.5 Expression Templates Assignments
27.3 Performance and Limitations of Expression Templates
27.4 Afternotes
28 Debugging Templates
28.1 Shallow Instantiation
28.2 Static Assertions
28.3 Archetypes
28.4 Tracers
28.5 Oracles

28.6 Afternotes
Appendixes
A The One-Definition Rule
A.1 Translation Units
A.2 Declarations and Definitions
A.3 The One-Definition Rule in Detail
A.3.1 One-per-Program Constraints
A.3.2 One-per-Translation Unit Constraints
A.3.3 Cross-Translation Unit Equivalence Constraints
B Value Categories
B.1 Traditional Lvalues and Rvalues
B.1.1 Lvalue-to-Rvalue Conversions
B.2 Value Categories Since C++11
B.2.1 Temporary Materialization
B.3 Checking Value Categories with decltype
B.4 Reference Types
C Overload Resolution
C.1 When Does Overload Resolution Kick In?
C.2 Simplified Overload Resolution
C.2.1 The Implied Argument for Member Functions
C.2.2 Refining the Perfect Match
C.3 Overloading Details
C.3.1 Prefer Nontemplates or More Specialized Templates
C.3.2 Conversion Sequences
C.3.3 Pointer Conversions
C.3.4 Initializer Lists
C.3.5 Functors and Surrogate Functions
C.3.6 Other Overloading Contexts
D Standard Type Utilities
D.1 Using Type Traits
D.1.1 std::integral_constant and std::bool_constant

D.1.2 Things You Should Know When Using Traits
D.2 Primary and Composite Type Categories
D.2.1 Testing for the Primary Type Category
D.2.2 Test for Composite Type Categories
D.3 Type Properties and Operations
D.3.1 Other Type Properties
D.3.2 Test for Specific Operations
D.3.3 Relationships Between Types
D.4 Type Construction
D.5 Other Traits
D.6 Combining Type Traits
D.7 Other Utilities
E Concepts
E.1 Using Concepts
E.2 Defining Concepts
E.3 Overloading on Constraints
E.3.1 Constraint Subsumption
E.3.2 Constraints and Tag Dispatching
E.4 Concept Tips
E.4.1 Testing Concepts
E.4.2 Concept Granularity
E.4.3 Binary Compatibility
Bibliography
Forums
Books and Web Sites
Glossary
Index

Preface
The notion of templates in C++ is over 30 years old. C++ templates were already
documented in 1990 in “The Annotated C++ Reference Manual” (ARM; see
[EllisStroustrupARM]), and they had been described before then in more
specialized publications. However, well over a decade later, we found a dearth of
literature that concentrates on the fundamental concepts and advanced
techniques of this fascinating, complex, and powerful C++ feature. With the first
edition of this book, we wanted to address this issue and decided to write the
book about templates (with perhaps a slight lack of humility).
Much has changed in C++ since that first edition was published in late 2002.
New iterations of the C++ standard have added new features, and continued
innovation in the C++ community has uncovered new template-based
programming techniques. The second edition of this book therefore retains the
same goals as the first edition, but for “Modern C++.”
We approached the task of writing this book with different backgrounds and
with different intentions. David (aka “Daveed”), an experienced compiler
implementer and active participant of the C++ Standard Committee working
groups that evolve the core language, was interested in a precise and detailed
description of all the power (and problems) of templates. Nico, an “ordinary”
application programmer and member of the C++ Standard Committee Library
Working Group, was interested in understanding all the techniques of templates
in a way that he could use and benefit from them. Doug, a template library
developer turned compiler implementer and language designer, was interested in
collecting, categorizing, and evaluating the myriad techniques used to build
template libraries. In addition, we all wanted to share this knowledge with you,
the reader, and the whole community to help to avoid further misunderstanding,
confusion, or apprehension.
As a consequence, you will see both conceptual introductions with day-to-day
examples and detailed descriptions of the exact behavior of templates. Starting
from the basic principles of templates and working up to the “art of template
programming,” you will discover (or rediscover) techniques such as static
polymorphism, type traits, metaprogramming, and expression templates. You
will also gain a deeper understanding of the C++ standard library, in which

almost all code involves templates.
We learned a lot and we had much fun while writing this book. We hope you
will have the same experience while reading it. Enjoy!

Acknowledgments for the Second Edition
Writing a book is hard. Maintaining a book is even harder. It took us more than
five years—spread over the past decade—to come up with this second edition,
and it couldn’t have been done without the support and patience of a lot of
people.
First, we’d like to thank everyone in the C++ community and on the C++
standardization committee. In addition to all the work to add new language and
library features, they spent many, many hours explaining and discussing their
work with us, and they did so with patience and enthusiasm.
Part of this community also includes the programmers who gave feedback for
errors and possible improvement for the first edition over the past 15 years.
There are simply too many to list them all, but you know who you are and we’re
truly grateful to you for taking the time to write up your thoughts and
observations. Please accept our apologies if our answers were sometimes less
than prompt.
We’d also like to thank everyone who reviewed drafts of this book and
provided us with valuable feedback and clarifications. These reviews brought the
book to a significantly higher level of quality, and it again proved that good
things need the input of many “wise guys.” For this reason, huge thanks to Steve
Dewhurst, Howard Hinnant, Mikael Kilpel¨ainen, Dietmar Kühl, Daniel Krügler,
Nevin Lieber, Andreas Neiser, Eric Niebler, Richard Smith, Andrew Sutton,
Hubert Tong, and Ville Voutilainen.
Of course, thanks to all the people who supported us from AddisonWesley/Pearson. These days, you can no longer take professional support for
book authors for granted. But they were patient, nagged us when appropriate,
and were of great help when knowledge and professionalism were necessary. So,
many thanks to Peter Gordon, Kim Boedigheimer, Greg Doench, Julie Nahil,
Dana Wilson, and Carol Lallier.
A special thanks goes to the LaTeX community for a great text system and to
Frank Mittelbach for solving our LATEX issues (it was almost always our fault).

David’s Acknowledgments for the Second Edition

This second edition was a long time in the waiting, and as we put the finishing
touches to it, I am grateful for the people in my life who made it possible despite
many obligations vying for attention. First, I’m indebted to my wife (Karina) and
daughters (Alessandra and Cassandra), for agreeing to let me take significant
time out of the “family schedule” to complete this edition, particularly in the last
year of work. My parents have always shown interest in my goals, and whenever
I visit them, they do not forget this particular project.
Clearly, this is a technical book, and its contents reflect knowledge and
experience about a programming topic. However, that is not enough to pull off
completing this kind of work. I’m therefore extremely grateful to Nico for
having taken upon himself the “management” and “production” aspects of this
edition (in addition to all of his technical contributions). If this book is useful to
you and you run into Nico some day, be sure to tell him thanks for keeping us all
going. I’m also thankful to Doug for having agreed to come on board several
years ago and to keep going even as demands on his own schedule made for
tough going.
Many programmers in our C++ community have shared nuggets of insight
over the years, and I am grateful to all of them. However, I owe special thanks to
Richard Smith, who has been efficiently answering my e-mails with arcane
technical issues for years now. In the same vein, thanks to my colleagues John
Spicer, Mike Miller, and Mike Herrick, for sharing their knowledge and creating
an encouraging work environment that allows us to learn ever more.

Nico’s Acknowledgments for the Second Edition
First, I want to thank the two hard-core experts, David and Doug, because, as an
application programmer and library expert, I asked so many silly questions and
learned so much. I now feel like becoming a core expert (only until the next
issue, of course). It was fun, guys.
All my other thanks go to Jutta Eckstein. Jutta has the wonderful ability to
force and support people in their ideals, ideas, and goals. While most people
experience this only occasionally when meeting her or working with her in our
IT industry, I have the honor to benefit from her in my day-to-day life. After all
these years, I still hope this will last forever.

Doug’s Acknowledgments for the Second Edition

My heartfelt thanks go to my wonderful and supportive wife, Amy, and our two
little girls, Molly and Tessa. Their love and companionship bring me daily joy
and the confidence to tackle the greatest challenges in life and work. I’d also like
to thank my parents, who instilled in me a great love of learning and encouraged
me throughout these years.
It was a pleasure to work with both David and Nico, who are so different in
personality yet complement each other so well. David brings a great clarity to
technical writing, honing in on descriptions that are precise and illuminating.
Nico, beyond his exceptional organizational skills that kept two coauthors from
wandering off into the weeds, brings a unique ability to take apart a complex
technical discussion and make it simpler, more accessible, and far, far clearer.

Acknowledgments for the First Edition
This book presents ideas, concepts, solutions, and examples from many sources.
We’d like to thank all the people and companies who helped and supported us
during the past few years.
First, we’d like to thank all the reviewers and everyone else who gave us their
opinion on early manuscripts. These people endow the book with a quality it
would never have had without their input. The reviewers for this book were Kyle
Blaney, Thomas Gschwind, Dennis Mancl, Patrick Mc Killen, and Jan Christiaan
van Winkel. Special thanks to Dietmar Kühl, who meticulously reviewed and
edited the whole book. His feedback was an incredible contribution to the
quality of this book.
We’d also like to thank all the people and companies who gave us the
opportunity to test our examples on different platforms with different compilers.
Many thanks to the Edison Design Group for their great compiler and their
support. It was a big help during the standardization process and the writing of
this book. Many thanks also go to all the developers of the free GNU and egcs
compilers (Jason Merrill was especially responsive) and to Microsoft for an
evaluation version of Visual C++ (Jonathan Caves, Herb Sutter, and Jason Shirk
were our contacts there).
Much of the existing “C++ wisdom” was collectively created by the online
C++ community. Most of it comes from the moderated Usenet groups
comp.lang.c++.moderated and comp.std.c++. We are therefore
especially indebted to the active moderators of those groups, who keep the
discussions useful and constructive. We also much appreciate all those who over
the years have taken the time to describe and explain their ideas for us all to
share.
The Addison-Wesley team did another great job. We are most indebted to
Debbie Lafferty (our editor) for her gentle prodding, good advice, and relentless
hard work in support of this book. Thanks also go to Tyrrell Albaugh, Bunny
Ames, Melanie Buck, Jacquelyn Doucette, Chanda Leary-Coutu, Catherine
Ohala, and Marty Rabinowitz. We’re grateful as well to Marina Lang, who first
sponsored this book within Addison-Wesley. Susan Winer contributed an early
round of editing that helped shape our later work.

Nico’s Acknowledgments for the First Edition
My first personal thanks go with a lot of kisses to my family: Ulli, Lucas, Anica,
and Frederic supported this book with a lot of patience, consideration, and
encouragement.
In addition, I want to thank David. His expertise turned out to be incredible,
but his patience was even better (sometimes I ask really silly questions). It is a
lot of fun to work with him.

David’s Acknowledgments for the First Edition
My wife, Karina, has been instrumental in this book coming to a conclusion, and
I am immensely grateful for the role that she plays in my life. Writing “in your
spare time” quickly becomes erratic when many other activities vie for your
schedule. Karina helped me to manage that schedule, taught me to say “no” in
order to make the time needed to make regular progress in the writing process,
and above all was amazingly supportive of this project. I thank God every day
for her friendship and love.
I’m also tremendously grateful to have been able to work with Nico. Besides
his directly visible contributions to the text, his experience and discipline moved
us from my pitiful doodling to a well-organized production.
John “Mr. Template” Spicer and Steve “Mr. Overload” Adamczyk are
wonderful friends and colleagues, but in my opinion they are (together) also the
ultimate authority regarding the core C++ language. They clarified many of the
trickier issues described in this book, and should you find an error in the
description of a C++ language element, it is almost certainly attributable to my
failing to consult with them.
Finally, I want to express my appreciation to those who were supportive of
this project without necessarily contributing to it directly (the power of cheer
cannot be understated). First, my parents: Their love for me and their
encouragement made all the difference. And then there are the numerous friends
inquiring: “How is the book going?” They, too, were a source of encouragement:
Michael Beckmann, Brett and Julie Beene, Jarran Carr, Simon Chang, Ho and
Sarah Cho, Christophe De Dinechin, Ewa Deelman, Neil Eberle, Sassan
Hazeghi, Vikram Kumar, Jim and Lindsay Long, R.J. Morgan, Mike Puritano,
Ragu Raghavendra, Jim and Phuong Sharp, Gregg Vaughn, and John Wiegley.

About This Book
The first edition of this book was published almost 15 years ago. We had set out
to write the definitive guide to C++ templates, with the expectation that it would
be useful to practicing C++ programmers. That project was successful: It’s been
tremendously gratifying to hear from readers who found our material helpful, to
see our book time and again being recommended as a work of reference, and to
be universally well reviewed.
That first edition has aged well, with most material remaining entirely relevant
to the modern C++ programmer, but there is no denying that the evolution of the
language—culminating in the “Modern C++” standards, C++11, C++14, and
C++17—has raised the need for a revision of the material in the first edition.
So with this second edition, our high-level goal has remained unchanged: to
provide the definitive guide to C++ templates, including both a solid reference
and an accessible tutorial. This time, however, we work with the “Modern C++”
language, which is a significantly bigger beast (still!) than the language available
at the time of the prior edition.
We’re also acutely aware that C++ programming resources have changed (for
the better) since the first edition was published. For example, several books have
appeared that develop specific template-based applications in great depth. More
important, far more information about C++ templates and template-based
techniques is easily available online, as are examples of advanced uses of these
techniques. So in this edition, we have decided to emphasize a breadth of
techniques that can be used in a variety of applications.
Some of the techniques we presented in the first edition have become obsolete
because the C++ language now offers more direct ways of achieving the same
effects. Those techniques have been dropped (or relegated to minor notes), and
instead you’ll find new techniques that show the state-ofthe-art uses of the new
language.
We’ve now lived over 20 years with C++ templates, but the C++
programmers’ community still regularly finds new fundamental insights into the
way they can fit in our software development needs. Our goal with this book is
to share that knowledge but also to fully equip the reader to develop new
understanding and, perhaps, discover the next major C++ technique.

What You Should Know Before Reading This Book
To get the most from this book, you should already know C++. We describe the
details of a particular language feature, not the fundamentals of the language
itself. You should be familiar with the concepts of classes and inheritance, and
you should be able to write C++ programs using components such as IOstreams
and containers from the C++ standard library. You should also be familiar with
the basic features of “Modern C++”, such as auto, decltype, move
semantics, and lambdas. Nevertheless, we review more subtle issues as the need
arises, even when such issues aren’t directly related to templates. This ensures
that the text is accessible to experts and intermediate programmers alike.
We deal primarily with the C++ language revisions standardized in 2011,
2014, and 2017. However, at the time of this writing, the ink is barely dry on the
C++17 revision, and we expect that most of our readers will not be intimately
familiar with its details. All revisions had a significant impact on the behavior
and usage of templates. We therefore provide short introductions to those new
features that have the greatest bearing on our subject matter. However, our goal
is neither to introduce the modern C++ standards nor to provide an exhaustive
description of the changes from the prior versions of this standard ([C++98] and
[C++03]). Instead, we focus on templates as designed and used in C++, using
the modern C++ standards ([C++11], [C++14], and [C++17]) as our basis, and
we occasionally call out cases where the modern C++ standards enable or
encourage different techniques than the prior standards.

Overall Structure of the Book
Our goal is to provide the information necessary to start using templates and
benefit from their power, as well as to provide information that will enable
experienced programmers to push the limits of the state-of-the-art. To achieve
this, we decided to organize our text in parts: • Part I introduces the basic
concepts underlying templates. It is written in a tutorial style.
• Part II presents the language details and is a handy reference to templaterelated constructs.
• Part III explains fundamental design and coding techniques supported by C++
templates. They range from near-trivial ideas to sophisticated idioms.
Each of these parts consists of several chapters. In addition, we provide a few

appendixes that cover material not exclusively related to templates (e.g., an
overview of overload resolution in C++). An additional appendix covers
concepts, which is a fundamental extension to templates that has been included
in the draft for a future standard (C++20, presumably).
The chapters of Part I are meant to be read in sequence. For example, Chapter
3 builds on the material covered in Chapter 2. In the other parts, however, the
connection between chapters is considerably looser. Cross references will help
readers jump through the different topics.
Last, we provide a rather complete index that encourages additional ways to
read this book out of sequence.

How to Read This Book
If you are a C++ programmer who wants to learn or review the concepts of
templates, carefully read Part I, The Basics. Even if you’re quite familiar with
templates already, it may help to skim through this part quickly to familiarize
yourself with the style and terminology that we use. This part also covers some
of the logistical aspects of organizing your source code when it contains
templates.
Depending on your preferred learning method, you may decide to absorb the
many details of templates in Part II, or instead you could read about practical
coding techniques in Part III (and refer back to Part II for the more subtle
language issues). The latter approach is probably particularly useful if you
bought this book with concrete day-to-day challenges in mind.
The appendixes contain much useful information that is often referred to in
the main text. We have also tried to make them interesting in their own right.
In our experience, the best way to learn something new is to look at examples.
Therefore, you’ll find a lot of examples throughout the book. Some are just a
few lines of code illustrating an abstract concept, whereas others are complete
programs that provide a concrete application of the material. The latter kind of
examples will be introduced by a C++ comment describing the file containing
the program code. You can find these files at the Web site of this book at
http://www.tmplbook.com.

Some Remarks About Programming Style

C++ programmers use different programming styles, and so do we: The usual
questions about where to put whitespace, delimiters (braces, parentheses), and so
forth came up. We tried to be consistent in general, although we occasionally
make concessions to the topic at hand. For example, in tutorial sections, we may
prefer generous use of whitespace and concrete names to help visualize code,
whereas in more advanced discussions, a more compact style could be more
appropriate.
We do want to draw your attention to one slightly uncommon decision
regarding the declaration of types, parameters, and variables. Clearly, several
styles are possible: void foo (const int &x);
void foo (const int& x);
void foo (int const &x);
void foo (int const& x); Although it is a bit less common, we decided to use the
order int const rather than const int for “constant integer.” We have
two reasons for using this order. First, it provides for an easier answer to the
question, “What is constant?” It’s always what is in front of the const qualifier.
Indeed, although const int N = 100; is equivalent to
int const N = 100; there is no equivalent form for Click here to view
code image
int* const bookmark; // the pointer cannot change, but the value
pointed to can

that would place the const qualifier before the pointer operator *. In this
example, it is the pointer itself that is constant, not the int to which it points.
Our second reason has to do with a syntactical substitution principle that is
very common when dealing with templates. Consider the following two type
declarations using the typedef keyword:1
Click here to view code image
typedef char* CHARS;
typedef CHARS const CPTR; // constant pointer to chars

or using the using keyword: Click here to view code image
using CHARS = char*;
using CPTR = CHARS const; // constant pointer to chars

The meaning of the second declaration is preserved when we textually replace
CHARS with what it stands for: Click here to view code image
typedef char* const CPTR; // constant pointer to chars

or:

Click here to view code image
using CPTR = char* const; // constant pointer to chars

However, if we write const before the type it qualifies, this principle doesn’t
apply. Consider the alternative to our first two type definitions presented earlier:
Click here to view code image
typedef char* CHARS;
typedef const CHARS CPTR; // constant pointer to chars

Textually replacing CHARS results in a type with a different meaning: Click here
to view code image
typedef const char* CPTR; // pointer to constant chars

The same observation applies to the volatile specifier, of course.
Regarding whitespaces, we decided to put the space between the ampersand
and the parameter name: void foo (int const& x); By doing this, we emphasize
the separation between the parameter type and the parameter name. This is
admittedly more confusing for declarations such as char* a, b; where, according
to the rules inherited from C, a is a pointer but b is an ordinary char. To avoid
such confusion, we simply avoid declaring multiple entities in this way.
This is primarily a book about language features. However, many techniques,
features, and helper templates now appear in the C++ standard library. To
connect these two, we therefore demonstrate template techniques by illustrating
how they are used to implement certain library components, and we use standard
library utilities to build our own more complex examples. Hence, we use not
only headers such as  and  (which contain templates
but are not particularly relevant to define other templates) but also ,
, , and  (which do provide
building blocks for more complex templates).
In addition, we provide a reference, Appendix D, about the major template
utilities provided by the C++ standard library, including a detailed description of
all the standard type traits. These are commonly used at the core of sophisticated
template programming

The C++11, C++14, and C++17 Standards
The original C++ standard was published in 1998 and subsequently amended by
a technical corrigendum in 2003, which provided minor corrections and

clarifications to the original standard. This “old C++ standard” is known as
C++98 or C++03.
The C++11 standard was the first major revision of C++ driven by the ISO
C++ standardization committee, bringing a wealth of new features to the
language. A number of these new features interact with templates and are
described in this book, including: • Variadic templates
• Alias templates
• Move semantics, rvalue references, and perfect forwarding • Standard type
traits
C++14 and C++17 followed, both introducing some new language features,
although the changes brought about by these standards were not quite as
dramatic as those of C++11.2 New features interacting with templates and
described in this book include but are not limited to: • Variable templates
(C++14) • Generic Lambdas (C++14)
• Class template argument deduction (C++17) • Compile-time if (C++17) •
Fold expressions (C++17)
We even describe concepts (template interfaces), which are currently slated for
inclusion in the forthcoming C++20 standard.
At the time of this writing, the C++11 and C++14 standards are broadly
supported by the major compilers, and C++17 is largely supported also. Still,
compilers differ greatly in their support of the different language features.
Several will compile most of the code in this book, but a few compilers may not
be able to handle some of our examples. However, we expect that this problem
will soon be resolved as programmers everywhere demand standard support
from their vendors.
Even so, the C++ programming language is likely to continue to evolve as
time passes. The experts of the C++ community (regardless of whether they
participate in the C++ Standardization Committee) are discussing various ways
to improve the language, and already several candidate improvements affect
templates. Chapter 17 presents some trends in this area.

Example Code and Additional Information
You can access all example programs and find more information about this book
from its Web site, which has the following URL: http://www.tmplbook.com

Feedback
We welcome your constructive input—both the negative and the positive. We
worked very hard to bring you what we hope you’ll find to be an excellent book.
However, at some point we had to stop writing, reviewing, and tweaking so we
could “release the product.” You may therefore find errors, inconsistencies, and
presentations that could be improved, or topics that are missing altogether. Your
feedback gives us a chance to inform all readers through the book’s Web site and
to improve any subsequent editions.
The best way to reach us is by email. You will find the email address at the
Web site of this book: http://www.tmplbook.com
Please, be sure to check the book’s Web site for the currently known errata
before submitting reports. Many thanks.
1

Note that in C++, a type definition defines a “type alias” rather than a new
type (see Section 2.8 on page 38).
For example:

>typedef int Length; // define Length as an alias for int
int i = 42;
Length l = 88;
i = l; // OK
l = i; // OK
2

The committee now aims at issuing a new standard roughly every 3 years.
Clearly, that leaves less time for massive additions, but it brings the changes
more quickly to the broader programming community. The development of
larger features, then, spans time and might cover multiple standards.

Part I
The Basics
This part introduces the general concepts and language features of C++
templates. It starts with a discussion of the general goals and concepts by
showing examples of function templates and class templates. It continues with
some additional fundamental template features such as nontype template
parameters, variadic templates, the keyword typename, and member
templates. Also it discusses how to deal with move semantics, how to declare
parameters, and how to use generic code for compile-time programming. It ends
with some general hints about terminology and regarding the use and application
of templates in practice both as application programmer and author of generic
libraries.

Why Templates?
C++ requires us to declare variables, functions, and most other kinds of entities
using specific types. However, a lot of code looks the same for different types.
For example, the implementation of the algorithm quicksort looks structurally
the same for different data structures, such as arrays of ints or vectors of
strings, as long as the contained types can be compared to each other.
If your programming language doesn’t support a special language feature for
this kind of genericity, you only have bad alternatives: 1. You can implement the
same behavior again and again for each type that needs this behavior.
2. You can write general code for a common base type such as Object or
void*.
3. You can use special preprocessors.
If you come from other languages, you probably have done some or all of this
before. However, each of these approaches has its drawbacks: 1. If you
implement a behavior again and again, you reinvent the wheel. You make the

same mistakes, and you tend to avoid complicated but better algorithms because
they lead to even more mistakes.
2. If you write general code for a common base class, you lose the benefit of
type checking. In addition, classes may be required to be derived from special
base classes, which makes it more difficult to maintain your code.
3. If you use a special preprocessor, code is replaced by some “stupid text
replacement mechanism” that has no idea of scope and types, which might
result in strange semantic errors. Templates are a solution to this problem
without these drawbacks. They are functions or classes that are written for one
or more types not yet specified. When you use a template, you pass the types
as arguments, explicitly or implicitly. Because templates are language
features, you have full support of type checking and scope.
In today’s programs, templates are used a lot. For example, inside the C++
standard library almost all code is template code. The library provides sort
algorithms to sort objects and values of a specified type, data structures (also
called container classes) to manage elements of a specified type, strings for
which the type of a character is parameterized, and so on. However, this is only
the beginning. Templates also allow us to parameterize behavior, to optimize
code, and to parameterize information. These applications are covered in later
chapters. Let’s first start with some simple templates.

Chapter 1
Function Templates
This chapter introduces function templates. Function templates are functions that
are parameterized so that they represent a family of functions.

1.1 A First Look at Function Templates
Function templates provide a functional behavior that can be called for different
types. In other words, a function template represents a family of functions. The
representation looks a lot like an ordinary function, except that some elements of
the function are left undetermined: These elements are parameterized. To
illustrate, let’s look at a simple example.

1.1.1 Defining the Template
The following is a function template that returns the maximum of two values:
Click here to view code image
basics/max1.hpp
template
T max (T a, T b)
{
// if b < a then yield a else yield b
return b < a ? a : b;
}

This template definition specifies a family of functions that return the maximum
of two values, which are passed as function parameters a and b.1 The type of
these parameters is left open as template parameter T. As seen in this example,
template parameters must be announced with syntax of the following form:
Click here to view code image

template< comma-separated-list-of-parameters > In our example, the
list of parameters is typename T. Note how the < and > tokens are
used as brackets; we refer to these as angle brackets. The keyword
typename introduces a type parameter. This is by far the most common
kind of template parameter in C++ programs, but other parameters are
possible, and we discuss them later (see Chapter 3).

Here, the type parameter is T. You can use any identifier as a parameter name,
but using T is the convention. The type parameter represents an arbitrary type
that is determined by the caller when the caller calls the function. You can use
any type (fundamental type, class, and so on) as long as it provides the
operations that the template uses. In this case, type T has to support operator <
because a and b are compared using this operator. Perhaps less obvious from the
definition of max() is that values of type T must also be copyable in order to be
returned.2
For historical reasons, you can also use the keyword class instead of
typename to define a type parameter. The keyword typename came
relatively late in the evolution of the C++98 standard. Prior to that, the keyword
class was the only way to introduce a type parameter, and this remains a valid
way to do so. Hence, the template max() could be defined equivalently as
follows: Click here to view code image
template
T max (T a, T b)
{
return b < a ? a : b;
}

Semantically there is no difference in this context. So, even if you use class
here, any type may be used for template arguments. However, because this use
of class can be misleading (not only class types can be substituted for T), you
should prefer the use of typename in this context. However, note that unlike
class type declarations, the keyword struct cannot be used in place of
typename when declaring type parameters.

1.1.2 Using the Template
The following program shows how to use the max() function template: Click
here to view code image
basics/max1.cpp

#include "max1.hpp"
#include 
#include 
int main()
{
int i = 42;
std::cout << "max(7,i): " << ::max(7,i) << ’\n’;
double f1 = 3.4; double f2 = -6.7;
std::cout << "max(f1,f2): " << ::max(f1,f2) << ’\n’;
std::string s1 = "mathematics"; std::string s2 = "math";
std::cout << "max(s1,s2): " << ::max(s1,s2) << ’\n’;
}

Inside the program, max() is called three times: once for two ints, once for
two doubles, and once for two std::strings. Each time, the maximum is
computed. As a result, the program has the following output: Click here to view
code image
max(7,i): 42
max(f1,f2): 3.4
max(s1,s2): mathematics

Note that each call of the max() template is qualified with ::. This is to ensure
that our max() template is found in the global namespace. There is also a
std::max() template in the standard library, which under some circumstances
may be called or may lead to ambiguity.3
Templates aren’t compiled into single entities that can handle any type.
Instead, different entities are generated from the template for every type for
which the template is used.4 Thus, max() is compiled for each of these three
types. For example, the first call of max()
int i = 42;
… max(7,i) …

uses the function template with int as template parameter T. Thus, it has the
semantics of calling the following code: int max (int a, int b)
{
return b < a ? a : b;
}
The process of replacing template parameters by concrete types is called
instantiation. It results in an instance of a template.5
Note that the mere use of a function template can trigger such an instantiation
process. There is no need for the programmer to request the instantiation

separately.
Similarly, the other calls of max() instantiate the max template for double
and std::string as if they were declared and implemented individually:
Click here to view code image
double max (double, double);
std::string max (std::string, std::string);

Note also that void is a valid template argument provided the resulting code is
valid. For example: Click here to view code image
template
T foo(T*)
{
}
void* vp = nullptr;
foo(vp); // OK: deduces void foo(void*)

1.1.3 Two-Phase Translation
An attempt to instantiate a template for a type that doesn’t support all the
operations used within it will result in a compile-time error. For example: Click
here to view code image
std::complex c1, c2; // doesn’t provide operator <
…
::max(c1,c2); // ERROR at compile time

Thus, templates are “compiled” in two phases: 1. Without instantiation at
definition time, the template code itself is checked for correctness ignoring the
template parameters. This includes: – Syntax errors are discovered, such as
missing semicolons.
– Using unknown names (type names, function names, …) that don’t depend
on template parameters are discovered.
– Static assertions that don’t depend on template parameters are checked.
2. At instantiation time, the template code is checked (again) to ensure that all
code is valid. That is, now especially, all parts that depend on template
parameters are double-checked.
For example:
Click here to view code image
template
void foo(T t)

{
undeclared(); // first-phase compile-time error if undeclared()
unknown
undeclared(t); // second-phase compile-time error if undeclared(T)
unknown
static_assert(sizeof(int) > 10, // always fails if sizeof(int)<=10
"int too small");
static_assert(sizeof(T) > 10, //fails if instantiated for T with size
<=10
"T too small");
}

The fact that names are checked twice is called two-phase lookup and discussed
in detail in Section 14.3.1 on page 249.
Note that some compilers don’t perform the full checks of the first phase.6 So
you might not see general problems until the template code is instantiated at
least once.

Compiling and Linking
Two-phase translation leads to an important problem in the handling of templates
in practice: When a function template is used in a way that triggers its
instantiation, a compiler will (at some point) need to see that template’s
definition. This breaks the usual compile and link distinction for ordinary
functions, when the declaration of a function is sufficient to compile its use.
Methods of handling this problem are discussed in Chapter 9. For the moment,
let’s take the simplest approach: Implement each template inside a header file.

1.2 Template Argument Deduction
When we call a function template such as max() for some arguments, the
template parameters are determined by the arguments we pass. If we pass two
ints to the parameter types T, the C++ compiler has to conclude that T must be
int.
However, T might only be “part” of the type. For example, if we declare
max() to use constant references: Click here to view code image
template
T max (T const& a, T const& b)
{
return b < a ? a : b;

}

and pass int, again T is deduced as int, because the function parameters
match for int const&.
Type Conversions During Type Deduction
Note that automatic type conversions are limited during type deduction: • When
declaring call parameters by reference, even trivial conversions do not apply to
type deduction. Two arguments declared with the same template parameter T
must match exactly.
• When declaring call parameters by value, only trivial conversions that decay
are supported: Qualifications with const or volatile are ignored,
references convert to the referenced type, and raw arrays or functions convert
to the corresponding pointer type. For two arguments declared with the same
template parameter T the decayed types must match.
For example:
Click here to view code image
template
T max (T a, T b);
…
int const c = 42;
max(i, c); // OK: T is deduced as int
max(c, c); // OK: T is deduced as int
int& ir = i;
max(i, ir); // OK: T is deduced as int
int arr[4];
foo(&i, arr); // OK: T is deduced as int*

However, the following are errors: Click here to view code image
max(4, 7.2); // ERROR: T can be deduced as int or double
std::string s;
foo("hello", s); //ERROR: T can be deduced as char const[6] or
std::string

There are three ways to handle such errors: 1. Cast the arguments so that they
both match: Click here to view code image
max(static_cast(4), 7.2); // OK

2. Specify (or qualify) explicitly the type of T to prevent the compiler from
attempting type deduction: Click here to view code image
max(4, 7.2); // OK

3. Specify that the parameters may have different types.
Section 1.3 on page 9 will elaborate on these options. Section 7.2 on page 108
and Chapter 15 will discuss the rules for type conversions during type deduction
in detail.
Type Deduction for Default Arguments
Note also that type deduction does not work for default call arguments. For
example: Click here to view code image
template
void f(T = "");
…
Click here to view code image
f(1); // OK: deduced T to be int, so that it calls f(1)
f(); // ERROR: cannot deduce T

To support this case, you also have to declare a default argument for the template
parameter, which will be discussed in Section 1.4 on page 13: Click here to view
code image
template
void f(T = "");
…
f(); // OK

1.3 Multiple Template Parameters
As we have seen so far, function templates have two distinct sets of parameters:
1. Template parameters, which are declared in angle brackets before the function
template name: Click here to view code image
template // T is template parameter

2. Call parameters, which are declared in parentheses after the function template
name: Click here to view code image
T max (T a, T b) // a and b are call parameters

You may have as many template parameters as you like. For example, you could
define the max() template for call parameters of two potentially different types:
Click here to view code image

template
T1 max (T1 a, T2 b)
{
return b < a ? a : b; }
…
auto m = ::max(4, 7.2); // OK, but type of first argument defines
return type

It may appear desirable to be able to pass parameters of different types to the
max() template, but, as this example shows, it raises a problem. If you use one
of the parameter types as return type, the argument for the other parameter might
get converted to this type, regardless of the caller’s intention. Thus, the return
type depends on the call argument order. The maximum of 66.66 and 42 will be
the double 66.66, while the maximum of 42 and 66.66 will be the int 66.
C++ provides different ways to deal with this problem: • Introduce a third
template parameter for the return type.
• Let the compiler find out the return type.
• Declare the return type to be the “common type” of the two parameter types.
All these options are discussed next.

1.3.1 Template Parameters for Return Types
Our earlier discussion showed that template argument deduction allows us to call
function templates with syntax identical to that of calling an ordinary function:
We do not have to explicitly specify the types corresponding to the template
parameters.
We also mentioned, however, that we can specify the types to use for the
template parameters explicitly: Click here to view code image
template
T max (T a, T b);
…
::max(4, 7.2); // instantiate T as double

In cases when there is no connection between template and call parameters and
when template parameters cannot be determined, you must specify the template
argument explicitly with the call. For example, you can introduce a third
template argument type to define the return type of a function template: Click
here to view code image
template
RT max (T1 a, T2 b);

However, template argument deduction does not take return types into account,7
and RT does not appear in the types of the function call parameters. Therefore,
RT cannot be deduced.8
As a consequence, you have to specify the template argument list explicitly.
For example: Click here to view code image
template
RT max (T1 a, T2 b);
…
::max(4, 7.2); // OK, but tedious

So far, we have looked at cases in which either all or none of the function
template arguments were mentioned explicitly. Another approach is to specify
only the first arguments explicitly and to allow the deduction process to derive
the rest. In general, you must specify all the argument types up to the last
argument type that cannot be determined implicitly. Thus, if you change the
order of the template parameters in our example, the caller needs to specify only
the return type: Click here to view code image
template
RT max (T1 a, T2 b);
…
::max(4, 7.2) //OK: return type is double, T1 and T2 are
deduced

In this example, the call to max explicitly sets RT to double, but
the parameters T1 and T2 are deduced to be int and double from the
arguments.
Note that these modified versions of max() don’t lead to significant
advantages. For the one-parameter version you can already specify the parameter
(and return) type if two arguments of a different type are passed. Thus, it’s a
good idea to keep it simple and use the one-parameter version of max() (as we
do in the following sections when discussing other template issues).
See Chapter 15 for details of the deduction process.

1.3.2 Deducing the Return Type
If a return type depends on template parameters, the simplest and best approach
to deduce the return type is to let the compiler find out. Since C++14, this is
possible by simply not declaring any return type (you still have to declare the
return type to be auto): Click here to view code image

basics/maxauto.hpp
template
auto max (T1 a, T2 b)
{
return b < a ? a : b;
}

In fact, the use of auto for the return type without a corresponding trailing
return type (which would be introduced with a -> at the end) indicates that the
actual return type must be deduced from the return statements in the function
body. Of course, deducing the return type from the function body has to be
possible. Therefore, the code must be available and multiple return statements
have to match.
Before C++14, it is only possible to let the compiler determine the return type
by more or less making the implementation of the function part of its
declaration. In C++11 we can benefit from the fact that the trailing return type
syntax allows us to use the call parameters. That is, we can declare that the
return type is derived from what operator?: yields: Click here to view code
image
basics/maxdecltype.hpp
template
auto max (T1 a, T2 b) -> decltype(b
auto max (T1 a, T2 b) -> decltype(b

auto max (T1 a, T2 b) -> decltype(true?a:b); However, in any case
this definition has a significant drawback: It might happen that the
return type is a reference type, because under some conditions T
might be a reference. For this reason you should return the type
decayed from T, which looks as follows: Click here to view code image

basics/maxdecltypedecay.hpp
#include 
template
auto max (T1 a, T2 b) -> typename std::decay::type
{ return b < a ? a : b;
}

Here, the type trait std::decay<> is used, which returns the resulting type in
a member type. It is defined by the standard library in  (see
Section D.5 on page 732). Because the member type is a type, you have to
qualify the expression with typename to access it (see Section 5.1 on page 67).
Note that an initialization of type auto always decays. This also applies to
return values when the return type is just auto. auto as a return type behaves
just as in the following code, where a is declared by the decayed type of i, int:
Click here to view code image
int i = 42;
int const& ir = i; // ir refers to
i auto a = ir; // a is declared as new object of type int

1.3.3 Return Type as Common Type
Since C++11, the C++ standard library provides a means to specify choosing
“the more general type.” std::common_type<>::type yields the
“common type” of two (or more) different types passed as template arguments.
For example: Click here to view code image
basics/maxcommon.hpp
#include 
template
std::common_type_t max (T1 a, T2 b)
{
return b < a ? a : b;
}

Again, std::common_type is a type trait, defined in ,

which yields a structure having a type member for the resulting type. Thus, its
core usage is as follows: Click here to view code image
typename std::common_type::type //since C++11

However, since C++14 you can simplify the usage of traits like this by
appending _t to the trait name and skipping typename and ::type (see
Section 2.8 on page 40 for details), so that the return type definition simply
becomes: Click here to view code image
std::common_type_t // equivalent since C++14

The way std::common_type<> is implemented uses some tricky template
programming, which is discussed in Section 26.5.2 on page 622. Internally, it
chooses the resulting type according to the language rules of operator ?: or
specializations for specific types. Thus, both ::max(4, 7.2) and
::max(7.2, 4) yield the same value 7.2 of type double. Note that
std::common_type<> also decays. See Section D.5 on page 732 for details.

1.4 Default Template Arguments
You can also define default values for template parameters. These values are
called default template arguments and can be used with any kind of template.9
They may even refer to previous template parameters.
For example, if you want to combine the approaches to define the return type
with the ability to have multiple parameter types (as discussed in the section
before), you can introduce a template parameter RT for the return type with the
common type of the two arguments as default. Again, we have multiple options:
1. We can use operator?: directly. However, because we have to apply
operator?: before the call parameters a and b are declared, we can only use
their types: Click here to view code image
basics/maxdefault1.hpp
#include 
template>
RT max (T1 a, T2 b)
{
return b < a ? a : b;
}

Note again the usage of std::decay_t<> to ensure that no reference can be
returned.10
Note also that this implementation requires that we are able to call default
constructors for the passed types. There is another solution, using
std::declval, which, however, makes the declaration even more
complicated. See Section 11.2.3 on page 166 for an example.
2. We can also use the std::common_type<> type trait to specify the default
value for the return type: Click here to view code image
basics/maxdefault3.hpp
#include 
template>
RT max (T1 a, T2 b)
{
return b < a ? a : b;
}

Again, note that std::common_type<> decays so that the return value
can’t become a reference.
In all cases, as a caller, you can now use the default value for the return type:
Click here to view code image
auto a = ::max(4, 7.2); or specify the return type after all other
argument types explicitly: Click here to view code image
auto b = ::max(7.2, 4); However, again we
have the problem that we have to specify three types to be able to
specify the return type only. Instead, we would need the ability to
have the return type as the first template parameter, while still
being able to deduce it from the argument types. In principle, it is
possible to have default arguments for leading function template
parameters even if parameters without default arguments follow: Click
here to view code image
template
RT max (T1 a, T2 b)
{
return b < a ? a : b;
}

With this definition, for example, you can call: Click here to view code image
int i; long l;
…
max(i, l); // returns long (default argument of template parameter

for return type)
max(4, 42); // returns int as explicitly requested

However, this approach only makes sense, if there is a “natural” default for a
template parameter. Here, we need the default argument for the template
parameter to depend from previous template parameters. In principle, this is
possible as we discuss in Section 26.5.1 on page 621, but the technique depends
on type traits and complicates the definition.
For all these reasons, the best and easiest solution is to let the compiler deduce
the return type as proposed in Section 1.3.2 on page 11.

1.5 Overloading Function Templates
Like ordinary functions, function templates can be overloaded. That is, you can
have different function definitions with the same function name so that when
that name is used in a function call, a C++ compiler must decide which one of
the various candidates to call. The rules for this decision may become rather
complicated, even without templates. In this section we discuss overloading
when templates are involved. If you are not familiar with the basic rules of
overloading without templates, please look at Appendix C, where we provide a
reasonably detailed survey of the overload resolution rules.
The following short program illustrates overloading a function template: Click
here to view code image
basics/max2.cpp
// maximum of two int values:
int max (int a,
int b)
{
return b < a ? a : b;
}
// maximum of two values of any type:
template
T max (T a, T b)
{
return b < a ? a : b;
}
int main()
{
::max(7, 42); // calls the nontemplate for two ints
::max(7.0, 42.0); // calls max (by argument deduction)
::max(’a’, ’b’); //calls max (by argument deduction)

::max<>(7, 42); // calls max (by argument deduction)
::max(7, 42); // calls max (no argument deduction)
::max(’a’, 42.7); //calls the nontemplate for two ints
}

As this example shows, a nontemplate function can coexist with a function
template that has the same name and can be instantiated with the same type. All
other factors being equal, the overload resolution process prefers the
nontemplate over one generated from the template. The first call falls under this
rule: Click here to view code image
::max(7, 42); // both int values match the nontemplate function
perfectly

If the template can generate a function with a better match, however, then the
template is selected. This is demonstrated by the second and third calls of
max(): Click here to view code image
::max(7.0, 42.0); // calls the max (by argument deduction)
::max(’a’, ’b’); //calls the max (by argument deduction)

Here, the template is a better match because no conversion from double or
char to int is required (see Section C.2 on page 682 for the rules of overload
resolution).
It is also possible to specify explicitly an empty template argument list. This
syntax indicates that only templates may resolve a call, but all the template
parameters should be deduced from the call arguments: Click here to view code
image
::max<>(7, 42); // calls max (by argument deduction)

Because automatic type conversion is not considered for deduced template
parameters but is considered for ordinary function parameters, the last call uses
the nontemplate function (while ’a’ and 42.7 both are converted to int):
Click here to view code image
::max(’a’, 42.7); //only the nontemplate function allows nontrivial
conversions

An interesting example would be to overload the maximum template to be able
to explicitly specify the return type only: Click here to view code image
basics/maxdefault4.hpp
template
auto max (T1 a, T2 b)
{

return b < a ? a : b;
}
template
RT max (T1 a, T2 b)
{
return b < a ? a : b;
}

Now, we can call max(), for example, as follows: Click here to view code
image
auto a = ::max(4, 7.2); // uses first template
auto b = ::max(7.2, 4); // uses second template

However, when calling:
Click here to view code image
auto c = ::max(4, 7.2); // ERROR: both function templates match

both templates match, which causes the overload resolution process normally to
prefer none and result in an ambiguity error. Thus, when overloading function
templates, you should ensure that only one of them matches for any call.
A useful example would be to overload the maximum template for pointers
and ordinary C-strings: Click here to view code image
basics/max3val.cpp
#include 
#include 
// maximum of two values of any type:
template
T max (T a, T b)
{
return b < a ? a : b;
}
// maximum of two pointers:
template
T* max (T* a, T* b)
{
return *b < *a ? a : b;
}
// maximum of two C-strings:
char const* max (char const* a, char const* b)
{
return std::strcmp(b,a) < 0 ? a : b;
}

int main ()
{
int a = 7;
int b = 42;
auto m1 = ::max(a,b); // max() for two values of type int
std::string s1 = "hey"; "
std::string s2 = "you"; "
auto m2 = ::max(s1,s2); // max() for two values of type std::string
int* p1 = &b;
int* p2 = &a;
auto m3 = ::max(p1,p2); // max() for two pointers
char const* x = hello"; "
char const* y = "world"; "
auto m4 = ::max(x,y); // max() for two C-strings
}

Note that in all overloads of max() we pass the arguments by value. In general,
it is a good idea not to change more than necessary when overloading function
templates. You should limit your changes to the number of parameters or to
specifying template parameters explicitly. Otherwise, unexpected effects may
happen. For example, if you implement your max() template to pass the
arguments by reference and overload it for two C-strings passed by value, you
can’t use the three-argument version to compute the maximum of three Cstrings: Click here to view code image
basics/max3ref.cpp
#include 
// maximum of two values of any type (call-by-reference)
template T const& max (T const& a, T const& b)
{
return b < a ? a : b;
}
// maximum of two C-strings (call-by-value)
char const* max (char const* a, char const* b)
{
return std::strcmp(b,a) < 0 ? a : b;
}
// maximum of three values of any type (call-by-reference)
template
T const& max (T const& a, T const& b, T const& c)
{

return max (max(a,b), c); // error if max(a,b) uses call-by-value
}
int main ()
{
auto m1 = ::max(7, 42, 68); // OK
char const* s1 = "frederic";
char const* s2 = "anica";
char const* s3 = "lucas";
auto m2 = ::max(s1, s2, s3); //run-time ERROR
}

The problem is that if you call max() for three C-strings, the statement Click
here to view code image
return max (max(a,b), c); becomes a run-time error because for Cstrings, max(a,b) creates a new, temporary local value that is
returned by reference, but that temporary value expires as soon as
the return statement is complete, leaving main() with a dangling
reference. Unfortunately, the error is quite subtle and may not
manifest itself in all cases.11

Note, in contrast, that the first call to max() in main() doesn’t suffer from
the same issue. There temporaries are created for the arguments (7, 42, and 68),
but those temporaries are created in main() where they persist until the
statement is done.
This is only one example of code that might behave differently than expected
as a result of detailed overload resolution rules. In addition, ensure that all
overloaded versions of a function are declared before the function is called. This
is because the fact that not all overloaded functions are visible when a
corresponding function call is made may matter. For example, defining a threeargument version of max() without having seen the declaration of a special
two-argument version of max() for ints causes the two-argument template to
be used by the three-argument version: basics/max4.cpp
Click here to view code image
#include 
// maximum of two values of any type:
template
T max (T a, T b)
{
std::cout << "max() \n";
return b < a ? a : b;
}
// maximum of three values of any type:
template

T max (T a, T b, T c)
{
return max (max(a,b), c); // uses the template version even for ints
} //because the following declaration comes
// too late:
// maximum of two int values:
int max (int a,
int b)
{
std::cout << "max(int,int) \n";
return b < a ? a : b;
}
int main()
{
::max(47,11,33); // OOPS: uses max() instead of max(int,int)
}

We discuss details in Section 13.2 on page 217.

1.6 But, Shouldn’t We …?
Probably, even these simple function template examples might raise further
questions. Three questions are probably so common that we should discuss them
here briefly.

1.6.1 Pass by Value or by Reference?
You might wonder, why we in general declare the functions to pass the
arguments by value instead of using references. In general, passing by reference
is recommended for types other than cheap simple types (such as fundamental
types or std::string_view), because no unnecessary copies are created.
However, for a couple of reasons, passing by value in general is often better: •
The syntax is simple.
• Compilers optimize better.
• Move semantics often makes copies cheap.
• And sometimes there is no copy or move at all.
In addition, for templates, specific aspects come into play: • A template might be
used for both simple and complex types, so choosing the approach for complex

types might be counter-productive for simple types.
• As a caller you can often still decide to pass arguments by reference, using
std::ref() and std::cref() (see Section 7.3 on page 112).
• Although passing string literals or raw arrays always can become a problem,
passing them by reference often is considered to become the bigger problem.
All this will be discussed in detail in Chapter 7. For the moment inside the
book we will usually pass arguments by value unless some functionality is only
possible when using references.

1.6.2 Why Not inline?
In general, function templates don’t have to be declared with inline. Unlike
ordinary noninline functions, we can define noninline function templates in a
header file and include this header file in multiple translation units.
The only exception to this rule are full specializations of templates for specific
types, so that the resulting code is no longer generic (all template parameters are
defined). See Section 9.2 on page 140 for more details.
From a strict language definition perspective, inline only means that a
definition of a function can appear multiple times in a program. However, it is
also meant as a hint to the compiler that calls to that function should be
“expanded inline”: Doing so can produce more efficient code for certain cases,
but it can also make the code less efficient for many other cases. Nowadays,
compilers usually are better at deciding this without the hint implied by the
inline keyword. However, compilers still account for the presence of
inline in that decision.

1.6.3 Why Not constexpr?
Since C++11, you can use constexpr to provide the ability to use code to
compute some values at compile time. For a lot of templates this makes sense.
For example, to be able to use the maximum function at compile time, you
have to declare it as follows: Click here to view code image
basics/maxconstexpr.hpp
template
constexpr auto max (T1 a, T2 b)

{
return b < a ? a : b;
}

With this, you can use the maximum function template in places with compiletime context, such as when declaring the size of a raw array: Click here to view
code image
int a[::max(sizeof(char),1000u)]; or the size of a std::array<>:
Click here to view code image
std::array arr; Note that we
pass 1000 as unsigned int to avoid warnings about comparing a signed
with an unsigned value inside the template.

Section 8.2 on page 125 will discuss other examples of using constexpr.
However, to keep our focus on the fundamentals, we usually will skip
constexpr when discussing other template features.

1.7 Summary
• Function templates define a family of functions for different template
arguments.
• When you pass arguments to function parameters depending on template
parameters, function templates deduce the template parameters to be
instantiated for the corresponding parameter types.
• You can explicitly qualify the leading template parameters.
• You can define default arguments for template parameters. These may refer to
previous template parameters and be followed by parameters not having
default arguments.
• You can overload function templates.
• When overloading function templates with other function templates, you
should ensure that only one of them matches for any call.
• When you overload function templates, limit your changes to specifying
template parameters explicitly.
• Ensure the compiler sees all overloaded versions of function templates before
you call them.
1

Note that the max() template according to [StepanovNotes] intentionally
returns “b < a ? a : b” instead of “a < b ? b : a” to ensure that
the function behaves correctly even if the two values are equivalent but not

equal.
Before C++17, type T also had to be copyable to be able to pass in arguments,
but since C++17 you can pass temporaries (rvalues, see Appendix B) even if
neither a copy nor a move constructor is valid.
3 For example, if one argument type is defined in namespace std (such as
std::string), according to the lookup rules of C++, both the global and
the max() template in std are found (see Appendix C).
4 A “one-entity-fits-all” alternative is conceivable but not used in practice (it
would be less efficient at run time). All language rules are based on the
principle that different entities are generated for different template arguments.
5 The terms instance and instantiate are used in a different context in objectoriented programming—namely, for a concrete object of a class. However,
because this book is about templates, we use this term for the “use” of
templates unless otherwise specified.
6 For example, The Visual C++ compiler in some versions (such as Visual
Studio 20133 and 2015) allow undeclared names that don’t depend on
template parameters and even some syntax flaws (such as a missing
semicolon).
7 Deduction can be seen as part of overload resolution—a process that is not
based on selection of return types either. The sole exception is the return type
of conversion operator members.
8 In C++, the return type also cannot be deduced from the context in which the
caller uses the call.
9 Prior to C++11, default template arguments were only permitted in class
templates, due to a historical glitch in the development of function templates.
10 Again, in C++11 you had to use typename std::decay<…>::type
instead of std::decay_t<…> (see Section 2.8 on page 40).
11 In general, a conforming compiler isn’t even permitted to reject this code.
2

Chapter 2
Class Templates
Similar to functions, classes can also be parameterized with one or more types.
Container classes, which are used to manage elements of a certain type, are a
typical example of this feature. By using class templates, you can implement
such container classes while the element type is still open. In this chapter we use
a stack as an example of a class template.

2.1 Implementation of Class Template Stack
As we did with function templates, we declare and define class Stack<> in a
header file as follows: Click here to view code image
basics/stack1.hpp
#include 
#include 
template
class Stack {
private:
std::vector elems; // elements
public:
void push(T const& elem); // push element
void pop(); // pop element
T const& top() const; // return top element
bool empty() const { // return whether the stack is empty
return elems.empty();
}
};
template
void Stack::push (T const& elem)
{
elems.push_back(elem); // append copy of passed elem}
template
void Stack::pop ()

{
assert(!elems.empty());
elems.pop_back(); // remove last element
}
template
T const& Stack::top () const
{
assert(!elems.empty());
return elems.back(); // return copy of last element
}

As you can see, the class template is implemented by using a class template of
the C++ standard library: vector<>. As a result, we don’t have to implement
memory management, copy constructor, and assignment operator, so we can
concentrate on the interface of this class template.

2.1.1 Declaration of Class Templates
Declaring class templates is similar to declaring function templates: Before the
declaration, you have to declare one or multiple identifiers as a type
parameter(s). Again, T is usually used as an identifier: Click here to view code
image
template
class Stack {
…
};

Here again, the keyword class can be used instead of typename: Click here
to view code image
template
class Stack {
…
};

Inside the class template, T can be used just like any other type to declare
members and member functions. In this example, T is used to declare the type of
the elements as vector of Ts, to declare push() as a member function that uses
a T as an argument, and to declare top() as a function that returns a T: Click
here to view code image
template<
typename T>
class Stack {

private:
std::vector elems; // elements
public:
void push(T const& elem); // push element
void pop(); // pop element
T const& top()
const; // return top element
bool empty() const { // return whether the stack is empty
return elems.empty();
}
};

The type of this class is Stack, with T being a template parameter. Thus,
you have to use Stack whenever you use the type of this class in a
declaration except in cases where the template arguments can be deduced.
However, inside a class template using the class name not followed by template
arguments represents the class with its template parameters as its arguments (see
Section 13.2.3 on page 221 for details).
If, for example, you have to declare your own copy constructor and
assignment operator, it typically looks like this: Click here to view code image
template
class Stack {
…
Stack (Stack const&); // copy constructor
Stack& operator= (Stack const&); // assignment operator
…
};

which is formally equivalent to: Click here to view code image
template
class Stack {
…
Stack (Stack const&); // copy constructor
Stack& operator= (Stack const&); // assignment operator
…
};

but usually the  signals special handling of special template parameters, so
it’s usually better to use the first form.
However, outside the class structure you’d need: Click here to view code
image
template
bool operator== (Stack const& lhs, Stack const& rhs); Note that
in places where the name and not the type of the class is required,
only Stack may be used. This is especially the case when you specify
the name of constructors (not their arguments) and the destructor.

Note also that, unlike nontemplate classes, you can’t declare or define class
templates inside functions or block scope. In general, templates can only be
defined in global/namespace scope or inside class declarations (see Section 12.1
on page 177 for details).

2.1.2 Implementation of Member Functions
To define a member function of a class template, you have to specify that it is a
template, and you have to use the full type qualification of the class template.
Thus, the implementation of the member function push() for type Stack
looks like this: Click here to view code image
template
void Stack::push (T const& elem)
{
elems.push_back(elem); // append copy of passed elem
}

In this case, push_back() of the element vector is called, which appends the
element at the end of the vector.
Note that pop_back() of a vector removes the last element but doesn’t
return it. The reason for this behavior is exception safety. It is impossible to
implement a completely exception-safe version of pop() that returns the
removed element (this topic was first discussed by Tom Cargill in
[CargillExceptionSafety] and is discussed as Item 10 in [SutterExceptional]).
However, ignoring this danger, we could implement a pop() that returns the
element just removed. To do this, we simply use T to declare a local variable of
the element type: Click here to view code image
template
T Stack::pop ()
{
assert(!elems.empty());
T elem = elems.back(); // save copy of last element
elems.pop_back(); // remove last element
return elem; // return copy of saved element
}

Because back() (which returns the last element) and pop_back() (which
removes the last element) have undefined behavior when there is no element in
the vector, we decided to check whether the stack is empty. If it is empty, we
assert, because it is a usage error to call pop() on an empty stack. This is also

done in top(), which returns but does not remove the top element, on attempts
to remove a nonexistent top element: Click here to view code image
template
T const& Stack::top () const
{
assert(!elems.empty());
return elems.back(); // return copy of last element
}

Of course, as for any member function, you can also implement member
functions of class templates as an inline function inside the class declaration. For
example: Click here to view code image
template
class Stack {
…
void push (T const& elem) {
elems.push_back(elem); // append copy of passed elem
}
…
};

2.2 Use of Class Template Stack
To use an object of a class template, until C++17 you must always specify the
template arguments explicitly.1 The following example shows how to use the
class template Stack<>: Click here to view code image
basics/stack1test.cpp
#include "stack1.hpp"
#include 
#include 
int main()
{
Stack< int> intStack; // stack of ints
Stack stringStack; // stack of strings
// manipulate int stack
intStack.push(7);
std::cout << intStack.top() << ’\n’;
// manipulate string stack
stringStack.push("hello");
std::cout << stringStack.top() << ’\n’;

stringStack.pop();
}

By declaring type Stack, int is used as type T inside the class
template. Thus, intStack is created as an object that uses a vector of ints as
elements and, for all member functions that are called, code for this type is
instantiated. Similarly, by declaring and using Stack, an
object that uses a vector of strings as elements is created, and for all member
functions that are called, code for this type is instantiated.
Note that code is instantiated only for template (member) functions that are
called. For class templates, member functions are instantiated only if they are
used. This, of course, saves time and space and allows use of class templates
only partially, which we will discuss in Section 2.3 on page 29.
In this example, the default constructor, push(), and top() are instantiated
for both int and strings. However, pop() is instantiated only for strings. If a
class template has static members, these are also instantiated once for each type
for which the class template is used.
An instantiated class template’s type can be used just like any other type. You
can qualify it with const or volatile or derive array and reference types
from it. You can also use it as part of a type definition with typedef or using
(see Section 2.8 on page 38 for details about type definitions) or use it as a type
parameter when building another template type. For example: Click here to view
code image
void foo(Stack  const& s) // parameter s is int
{
using IntStack = Stack ; // IntStack is another
Stack
Stack< int> istack[10]; // istack is array of 10 int
IntStack istack2[10]; // istack2 is also an array of
(same type)
…
}

stack
name for
stacks
10 int stacks

Template arguments may be any type, such as pointers to floats or even stacks
of ints: Click here to view code image
Stack< float*> floatPtrStack; // stack of float pointers
Stack> intStackStack; // stack of stack of ints

The only requirement is that any operation that is called is possible according to
this type.
Note that before C++11 you had to put whitespace between the two closing
template brackets: Click here to view code image

Stack > intStackStack; // OK with all C++ versions

If you didn’t do this, you were using operator >>, which resulted in a syntax
error: Click here to view code image
Stack> intStackStack; // ERROR before C++11

The reason for the old behavior was that it helped the first pass of a C++
compiler to tokenize the source code independent of the semantics of the code.
However, because the missing space was a typical bug, which required
corresponding error messages, the semantics of the code more and more had to
get taken into account anyway. So, with C++11 the rule to put a space between
two closing template brackets was removed with the “angle bracket hack” (see
Section 13.3.1 on page 226 for details).

2.3 Partial Usage of Class Templates
A class template usually applies multiple operations on the template arguments it
is instantiated for (including construction and destruction). This might lead to the
impression that these template arguments have to provide all operations
necessary for all member functions of a class template. But this is not the case:
Template arguments only have to provide all necessary operations that are
needed (instead of that could be needed).
If, for example, class Stack<> would provide a member function printOn()
to print the whole stack content, which calls operator<< for each element:
Click here to view code image
template
class Stack {
…
void printOn() (std::ostream& strm) const {
for (T const& elem : elems) {
strm << elem << ’ ’; // call << for each element
}
}
};

You can still use this class for elements that don’t have operator<< defined:
Click here to view code image
Stack> ps; // note: std::pair<> has no
operator<< defined
ps.push({4, 5}); // OK
ps.push({6, 7}); // OK
std::cout << ps.top().first << ’\n’; // OK

std::cout << ps.top().second << ’\n’; // OK

Only if you call printOn() for such a stack, the code will produce an error,
because it can’t instantiate the call of operator<< for this specific element
type: Click here to view code image
ps.printOn(std::cout); // ERROR: operator<< not supported for element
type

2.3.1 Concepts
This raises the question: How do we know which operations are required for a
template to be able to get instantiated? The term concept is often used to denote
a set of constraints that is repeatedly required in a template library. For example,
the C++ standard library relies on such concepts as random access iterator and
default constructible.
Currently (i.e., as of C++17), concepts can more or less only be expressed in
the documentation (e.g., code comments). This can become a significant
problem because failures to follow constraints can lead to terrible error messages
(see Section 9.4 on page 143).
For years, there have also been approaches and trials to support the definition
and validation of concepts as a language feature. However, up to C++17 no such
approach was standardized yet.
Since C++11, you can at least check for some basic constraints by using the
static_assert keyword and some predefined type traits. For example:
Click here to view code image
template
class C
{
static_assert(std::is_default_constructible::value,
"Class C requires default-constructible elements");
…
};

Without this assertion the compilation will still fail, if the default constructor is
required. However, the error message then might contain the entire template
instantiation history from the initial cause of the instantiation down to the actual
template definition in which the error was detected (see Section 9.4 on page
143).
However, more complicated code is necessary to check, for example, objects

of type T provide a specific member function or that they can be compared using
operator <. See Section 19.6.3 on page 436 for a detailed example of such code.
See Appendix E for a detailed discussion of concepts for C++.

2.4 Friends
Instead of printing the stack contents with printOn() it is better to implement
operator<< for the stack. However, as usual operator<< has to be
implemented as nonmember function, which then could call printOn() inline:
Click here to view code image
template
class Stack {
…
void printOn() (std::ostream& strm) const {
…
}
friend std::ostream& operator<< (std::ostream& strm,
Stack const& s) {
s.printOn(strm);
return strm;
}
};

Note that this means that operator<< for class Stack<> is not a function
template, but an “ordinary” function instantiated with the class template if
needed.2
However, when trying to declare the friend function and define it afterwards,
things become more complicated. In fact, we have two options: 1. We can
implicitly declare a new function template, which must use a different template
parameter, such as U: Click here to view code image
template
class Stack {
…
template
friend std::ostream& operator<< (std::ostream&, Stack const&);
};

Neither using T again nor skipping the template parameter declaration would
work (either the inner T hides the outer T or we declare a nontemplate
function in namespace scope).
2. We can forward declare the output operator for a Stack to be a template,

which, however, means that we first have to forward declare Stack:
Click here to view code image
template
class Stack;
template
std::ostream& operator<< (std::ostream&, Stack const&); Then, we
can declare this function as friend: Click here to view code image
template
class Stack {
…
friend std::ostream& operator<<  (std::ostream&,
Stack const&);
};

Note the  behind the “function name” operator<<. Thus, we declare a
specialization of the nonmember function template as friend. Without  we
would declare a new nontemplate function. See Section 12.5.2 on page 211 for
details.
In any case, you can still use this class for elements that don’t have operator<<
defined. Only calling operator<< for this stack results in an error: Click here to
view code image
Stack> ps; // std::pair<> has no operator<<
defined
ps.push({4, 5}); // OK
ps.push({6, 7}); // OK
std::cout <<
ps.top().first << ’\n’; // OK
std::cout <<
ps.top().second << ’\n’; // OK
std::cout << ps << ’\n’; // ERROR: operator<< not supported
// for element type

2.5 Specializations of Class Templates
You can specialize a class template for certain template arguments. Similar to the
overloading of function templates (see Section 1.5 on page 15), specializing
class templates allows you to optimize implementations for certain types or to
fix a misbehavior of certain types for an instantiation of the class template.
However, if you specialize a class template, you must also specialize all member
functions. Although it is possible to specialize a single member function of a
class template, once you have done so, you can no longer specialize the whole

class template instance that the specialized member belongs to.
To specialize a class template, you have to declare the class with a leading
template<> and a specification of the types for which the class template is
specialized. The types are used as a template argument and must be specified
directly following the name of the class: Click here to view code image
template<>
class Stack {
…
};

For these specializations, any definition of a member function must be defined
as an “ordinary” member function, with each occurrence of T being replaced by
the specialized type: Click here to view code image
void Stack::push (std::string const& elem)
{
elems.push_back(elem); // append copy of passed elem
}

Here is a complete example of a specialization of Stack<> for type
std::string: Click here to view code image
basics/stack2.hpp
#include
#include
#include
#include

"stack1.hpp"




template<>
class Stack {
private:
std::deque elems; // elements
public:
void push(std::string const&); // push element
void pop(); // pop element
std::string const& top() const; // return top element
bool empty() const { // return whether the stack is empty
return elems.empty();
}
};
void Stack::push (std::string const& elem)
{
elems.push_back(elem); // append copy of passed elem
}
void Stack::pop ()

{
assert(!elems.empty());
elems.pop_back(); // remove last element
}
std::string const& Stack::top () const
{
assert(!elems.empty());
return elems.back(); // return copy of last element
}

In this example, the specialization uses reference semantics to pass the string
argument to push(), which makes more sense for this specific type (we should
even better pass a forwarding reference, though, which is discussed in Section
6.1 on page 91).
Another difference is to use a deque instead of a vector to manage the
elements inside the stack. Although this has no particular benefit here, it does
demonstrate that the implementation of a specialization might look very different
from the implementation of the primary template.

2.6 Partial Specialization
Class templates can be partially specialized. You can provide special
implementations for particular circumstances, but some template parameters
must still be defined by the user. For example, we can define a special
implementation of class Stack<> for pointers: Click here to view code image
basics/stackpartspec.hpp
#include "stack1.hpp"
// partial specialization of class Stack<> for pointers:
template
class Stack {
private:
std::vector elems; // elements
public:
void push(T*); // push element
T* pop(); // pop element
T* top() const; // return top element
bool empty() const { // return whether the stack is empty
return elems.empty();
}
};

template
void Stack::push (T* elem)
{
elems.push_back(elem); // append copy of passed elem
}
template
T* Stack::pop ()
{
assert(!elems.empty());
T* p = elems.back();
elems.pop_back(); // remove last element
return p; // and return it (unlike in the general case)
}
template
T* Stack::top () const
{
assert(!elems.empty());
return elems.back(); // return copy of last element
}

With
Click here to view code image
template
class Stack {
};

we define a class template, still parameterized for T but specialized for a pointer
(Stack).
Note again that the specialization might provide a (slightly) different interface.
Here, for example, pop() returns the stored pointer, so that a user of the class
template can call delete for the removed value, when it was created with new:
Click here to view code image
Stack< int*> ptrStack; // stack of pointers (special implementation)
ptrStack.push(new int{42});
std::cout << *ptrStack.top() << ’\n’;
delete ptrStack.pop();

Partial Specialization with Multiple Parameters
Class templates might also specialize the relationship between multiple template
parameters. For example, for the following class template: Click here to view
code image

template
class MyClass {
…
};

the following partial specializations are possible: Click here to view code image
// partial specialization: both template parameters have same type
template
class MyClass {
…
};
// partial specialization: second type is int
template
class MyClass {
…
};
// partial specialization: both template parameters are pointer types
template
class MyClass {
…
};

The following examples show which template is used by which declaration:
Click here to view code image
MyClass<
MyClass<
MyClass<
MyClass<

int, float> mif; // uses MyClass
float, float> mff; // uses MyClass
float, int> mfi; // uses MyClass
int*, float*> mp; // uses MyClass

If more than one partial specialization matches equally well, the declaration is
ambiguous: Click here to view code image
MyClass< int, int> m; // ERROR: matches MyClass
// and MyClass
MyClass< int*, int*> m; // ERROR: matches MyClass
// and MyClass

To resolve the second ambiguity, you could provide an additional partial
specialization for pointers of the same type: Click here to view code image
template
class MyClass {
…
};

For details of partial specialization, see Section 16.4 on page 347.

2.7 Default Class Template Arguments
As for function templates, you can define default values for class template
parameters. For example, in class Stack<> you can define the container that is
used to manage the elements as a second template parameter, using
std::vector<> as the default value: Click here to view code image
basics/stack3.hpp
#include 
#include 
template>
class Stack {
private:
Cont elems; // elements
public:
void push(T const& elem); // push element
void pop(); // pop element
T const& top() const; // return top element
bool empty() const { // return whether the stack is empty
return elems.empty();
}
};
template
void Stack::push (T const& elem)
{
elems.push_back(elem); // append copy of passed elem}
template
void Stack::pop ()
{
assert(!elems.empty());
elems.pop_back(); // remove last element
}
template
T const& Stack::top () const
{
assert(!elems.empty());
return elems.back(); // return copy of last element
}

Note that we now have two template parameters, so each definition of a member
function must be defined with these two parameters: Click here to view code

image
template
void Stack::push (T const& elem)
{
elems.push_back(elem); // append copy of passed elem
}

You can use this stack the same way it was used before. Thus, if you pass a first
and only argument as an element type, a vector is used to manage the elements
of this type: Click here to view code image
template>
class Stack {
private:
Cont elems; // elements
…
};

In addition, you could specify the container for the elements when you declare a
Stack object in your program: Click here to view code image
basics/stack3test.cpp
#include "stack3.hpp"
#include 
#include 
int main()
{
// stack of ints:
Stack< int> intStack;
// stack of doubles using a std::deque<> to manage the elements
Stack< double,std::deque< double>> dblStack;
// manipulate int stack
intStack.push(7);
std::cout << intStack.top() << ’\n’;
intStack.pop();
// manipulate double stack
dblStack.push(42.42);
std::cout << dblStack.top() << ’\n’;
dblStack.pop();
}

With

Click here to view code image
Stack< double,std::deque< double>>

you declare a stack for doubles that uses a std::deque<> to manage the
elements internally.

2.8 Type Aliases
You can make using a class template more convenient by defining a new name
for the whole type.
Typedefs and Alias Declarations
To simply define a new name for a complete type, there are two ways to do it: 1.
By using the keyword typedef: Click here to view code image
typedef Stack
typedef Stack IntStack; // typedef
void foo (IntStack const& s); // s is stack ofints
IntStack istack[10]; // istack is array of 10 stacks of ints

We call this declaration a typedef3 and the resulting name is called a typedefname.
2. By using the keyword using (since C++11): Click here to view code image
using IntStack = Stack ; // alias declaration
void foo (IntStack const& s); // s is stack of ints
IntStack istack[10]; // istack is array of 10 stacks of ints

Introduced by [DosReisMarcusAliasTemplates], this is called an alias
declaration.
Note that in both cases we define a new name for an existing type rather than a
new type. Thus, after the typedef Click here to view code image
typedef Stack  IntStack; or
Click here to view code image
using IntStack = Stack ; IntStack and Stack are two
interchangeable notations for the same type.

As a common term for both alternatives to define a new name for an existing
type, we use the term type alias declaration. The new name is a type alias then.
Because it is more readable (always having the defined type name on the left
side of the =, for the remainder of this book, we prefer the alias declaration

syntax when declaring an type alias.
Alias Templates
Unlike a typedef, an alias declaration can be templated to provide a
convenient name for a family of types. This is also available since C++11 and is
called an alias template.4
The following alias template DequeStack, parameterized over the element
type T, expands to a Stack that stores its elements in a std::deque: Click
here to view code image
template
using DequeStack = Stack>; Thus, both class
templates and alias templates can be used as a parameterized type.
But again, an alias template simply gives a new name to an existing
type, which can still be used. Both DequeStack and Stack> represent the same type.

Note again that, in general, templates can only be declared and defined in
global/namespace scope or inside class declarations.
Alias Templates for Member Types
Alias templates are especially helpful to define shortcuts for types that are
members of class templates. After Click here to view code image
struct C {
typedef … iterator;
…
};

or:
Click here to view code image
struct MyType {
using iterator = …;
…
};

a definition such as
Click here to view code image
template
using MyTypeIterator = typename MyType::iterator; allows the use
of
Click here to view code image

MyTypeIterator< int> pos;

instead of the following:5
Click here to view code image
typename MyType::iterator pos;

Type Traits Suffix_t
Since C++14, the standard library uses this technique to define shortcuts for all
type traits in the standard library that yield a type. For example, to be able to
write Click here to view code image
std::add_const_t // since C++14

instead of
Click here to view code image
typename std::add_const::type // since C++11

the standard library defines:
Click here to view code image
namespace std {
template using add_const_t = typename add_const::type;
}

2.9 Class Template Argument Deduction
Until C++17, you always had to pass all template parameter types to class
templates (unless they have default values). Since C++17, the constraint that you
always have to specify the template arguments explicitly was relaxed. Instead,
you can skip to define the templates arguments explicitly, if the constructor is
able to deduce all template parameters (that don’t have a default value), For
example, in all previous code examples, you can use a copy constructor without
specifying the template arguments: Click here to view code image
Stack< int> intStack1; // stack of strings
Stack< int> intStack2 = intStack1; // OK in all versions
Stack intStack3 = intStack1; // OK since C++17

By providing constructors that pass some initial arguments, you can support
deduction of the element type of a stack. For example, we could provide a stack
that can be initialized by a single element: Click here to view code image

template
class Stack {
private:
std::vector elems; // elements
public:
Stack () = default;
Stack (T const& elem) // initialize stack with one element
: elems({elem}) {
}
…
};

This allows you to declare a stack as follows: Click here to view code image
Stack intStack = 0; // Stack deduced since C++17

By initializing the stack with the integer 0, the template parameter T is deduced
to be int, so that a Stack is instantiated.
Note the following: • Due to the definition of the int constructor, you have to
request the default constructors to be available with its default behavior, because
the default constructor is available only if no other constructor is defined:
Stack() = default;
• The argument elem is passed to elems with braces around to initialize the
vector elems with an initializer list with elem as the only argument: :
elems({elem})
There is no constructor for a vector that is able to take a single parameter as
initial element directly.6
Note that, unlike for function templates, class template arguments may not be
deduced only partially (by explicitly specifying only some of the template
arguments). See Section 15.12 on page 314 for details.
Class Template Arguments Deduction with String Literals
In principle, you can even initialize the stack with a string literal: Click here to
view code image
Stack stringStack = "bottom"; // Stack deduced since
C++17

But this causes a lot of trouble: In general, when passing arguments of a
template type T by reference, the parameter doesn’t decay, which is the term for
the mechanism to convert a raw array type to the corresponding raw pointer
type. This means that we really initialize a Stack< char const[7]>
and use type char const[7] wherever T is used. For example, we may not

push a string of different size, because it has a different type. For a detailed
discussion see Section 7.4 on page 115.
However, when passing arguments of a template type T by value, the
parameter decays, which is the term for the mechanism to convert a raw array
type to the corresponding raw pointer type. That is, the call parameter T of the
constructor is deduced to be char const* so that the whole class is deduced
to be a Stack.
For this reason, it might be worthwhile to declare the constructor so that the
argument is passed by value: Click here to view code image
template
class Stack {
private:
std::vector elems; // elements
public:
Stack (T elem) // initialize stack with one element by value
: elems({elem}) { // to decay on class tmpl arg deduction
}
…
};

With this, the following initialization works fine: Click here to view code image
Stack stringStack = "bottom"; // Stack deduced since
C++17

In this case, however, we should better move the temporary elem into the stack
to avoid unnecessarily copying it: Click here to view code image
template
class Stack {
private:
std::vector elems; // elements
public:
Stack (T elem) // initialize stack with one element by value
: elems({std::move(elem)}) {
}
…
};

Deduction Guides
Instead of declaring the constructor to be called by value, there is a different
solution: Because handling raw pointers in containers is a source of trouble, we
should disable automatically deducing raw character pointers for container
classes.
You can define specific deduction guides to provide additional or fix existing

class template argument deductions. For example, you can define that whenever
a string literal or C string is passed, the stack is instantiated for std::string:
Click here to view code image
Stack( char const*) -> Stack;

This guide has to appear in the same scope (namespace) as the class definition.
Usually, it follows the class definition. We call the type following the -> the
guided type of the deduction guide.
Now, the declaration with
Click here to view code image
Stack stringStack{"bottom"}; // OK: Stack deduced since
C++17

deduces the stack to be a Stack. However, the following
still doesn’t work: Click here to view code image
Stack stringStack = "bottom"; // Stack deduced, but
still not valid

We deduce std::string so that we instantiate a Stack:
Click here to view code image
class Stack {
private:
std::vector elems; // elements
public:
Stack (std::string const& elem) // initialize stack with one element
: elems({elem}) {
}
…
};

However, by language rules, you can’t copy initialize (initialize using =) an
object by passing a string literal to a constructor expecting a std::string. So
you have to initialize the stack as follows: Click here to view code image
Stack stringStack{"bottom"}; // Stack deduced and valid

Note that, if in doubt, class template argument deduction copies. After declaring
stringStack as Stack the following initializations
declare the same type (thus, calling the copy constructor) instead of initializing a
stack by elements that are string stacks: Click here to view code image
Stack stack2{stringStack}; // Stack deduced
Stack stack3(stringStack); // Stack deduced
Stack stack4 = {stringStack}; // Stack deduced

See Section 15.12 on page 313 for more details about class template argument
deduction.

2.10 Templatized Aggregates
Aggregate classes (classes/structs with no user-provided, explicit, or inherited
constructors, no private or protected nonstatic data members, no virtual
functions, and no virtual, private, or protected base classes) can also be
templates. For example: Click here to view code image
template
struct ValueWithComment {
T value;
std::string comment;
};

defines an aggregate parameterized for the type of the value val it holds. You
can declare objects as for any other class template and still use it as aggregate:
Click here to view code image
ValueWithComment< int> vc;
vc.value = 42;
vc.comment = "initial value"; Since C++17, you can even define
deduction guides for aggregate class templates: Click here to view
code image
ValueWithComment(
char const*, char const*)
-> ValueWithComment;
ValueWithComment vc2 = {"hello", "initial value"}; Without the
deduction guide, the initialization would not be possible, because
ValueWithComment has no constructor to perform the deduction against.

The standard library class std::array<> is also an aggregate,
parameterized for both the element type and the size. The C++17 standard
library also defines a deduction guide for it, which we discuss in Section 4.4.4
on page 64.

2.11 Summary
• A class template is a class that is implemented with one or more type
parameters left open.
• To use a class template, you pass the open types as template arguments. The

class template is then instantiated (and compiled) for these types.
• For class templates, only those member functions that are called are
instantiated.
• You can specialize class templates for certain types.
• You can partially specialize class templates for certain types.
• Since C++17, class template arguments can automatically be deduced from
constructors.
• You can define aggregate class templates.
• Call parameters of a template type decay if declared to be called by value.
• Templates can only be declared and defined in global/namespace scope or
inside class declarations.
1

C++17 introduced class argument template deduction, which allows skipping
template arguments if they can be derived from the constructor. This will be
discussed in Section 2.9 on page 40.
2 It is a templated entity, see Section 12.1 on page 181.
3 Using the word typedef instead of “type definition” in intentional. The
keyword typedef was originally meant to suggest “type definition.”
However, in C++, “type definition” really means something else (e.g., the
definition of a class or enumeration type). Instead, a typedef should just be
thought of as an alternative name (an “alias”) for an existing type, which can
be done by a typedef.
4 Alias templates are sometimes (incorrectly) referred to as typedef templates
because they fulfill the same role that a typedef would if it could be made
into a template.
5 The typename is necessary here because the member is a type. See Section
5.1 on page 67 for details.
6 Even worse, there is a vector constructor taking one integral argument as
initial size, so that for a stack with the initial value 5, the vector would get an
initial size of five elements when : elems(elem) is used.

Chapter 3
Nontype Template Parameters
For function and class templates, template parameters don’t have to be types.
They can also be ordinary values. As with templates using type parameters, you
define code for which a certain detail remains open until the code is used.
However, the detail that is open is a value instead of a type. When using such a
template, you have to specify this value explicitly. The resulting code then gets
instantiated. This chapter illustrates this feature for a new version of the stack
class template. In addition, we show an example of nontype function template
parameters and discuss some restrictions to this technique.

3.1 Nontype Class Template Parameters
In contrast to the sample implementations of a stack in previous chapters, you
can also implement a stack by using a fixed-size array for the elements. An
advantage of this method is that the memory management overhead, whether
performed by you or by a standard container, is avoided. However, determining
the best size for such a stack can be challenging. The smaller the size you
specify, the more likely it is that the stack will get full. The larger the size you
specify, the more likely it is that memory will be reserved unnecessarily. A good
solution is to let the user of the stack specify the size of the array as the
maximum size needed for stack elements.
To do this, define the size as a template parameter: Click here to view code
image
basics/stacknontype.hpp
#include 
#include 
template
class Stack {
private:
std::array elems; // elements

std::size_t numElems; // current number of elements
public:
Stack(); // constructor
void push(T const& elem); // push element
void pop(); // pop element
T const& top() const; // return top element
bool empty() const { //return whether the stack is empty
return numElems == 0;
}
std::size_t size() const { //return current number of elements
return numElems;
}
};
template
Stack::Stack ()
: numElems(0) //start with no elements
{
// nothing else to do
}
template
void Stack::push (T const& elem)
{
assert(numElems < Maxsize);
elems[numElems] = elem; // append element
++numElems; // increment number of elements
}
template
void Stack::pop ()
{
assert(!elems.empty());
--numElems; // decrement number of elements
}
template
T const& Stack::top () const
{
assert(!elems.empty());
return elems[numElems-1]; // return last element
}

The new second template parameter, Maxsize, is of type int. It specifies the
size of the internal array of stack elements: Click here to view code image
template
class Stack {
private:
std::array elems; // elements
…
};

In addition, it is used in push() to check whether the stack is full: Click here to
view code image
template
void Stack::push (T const& elem)
{
assert(numElems < Maxsize);
elems[numElems] = elem; // append element ++numElems; // increment
number of elements
}

To use this class template you have to specify both the element type and the
maximum size: Click here to view code image
basics/stacknontype.cpp
#include "stacknontype.hpp"
#include 
#include 
int main()
{
Stack int20Stack; // stack of up to 20 ints
Stack int40Stack; // stack of up to 40 ints
Stack stringStack; // stack of up to 40 strings
// manipulate stack of up to 20 ints
int20Stack.push(7);
std::cout << int20Stack.top() << ’\n’;
int20Stack.pop();
// manipulate stack of up to 40 strings
stringStack.push("hello");
std::cout << stringStack.top() << ’\n’;
stringStack.pop();
}

Note that each template instantiation is its own type. Thus, int20Stack and
int40Stack are two different types, and no implicit or explicit type
conversion between them is defined. Thus, one cannot be used instead of the
other, and you cannot assign one to the other.
Again, default arguments for the template parameters can be specified: Click
here to view code image
template
class Stack {
…
};

However, from a perspective of good design, this may not be appropriate in this
example. Default arguments should be intuitively correct. But neither type int
nor a maximum size of 100 seems intuitive for a general stack type. Thus, it is
better when the programmer has to specify both values explicitly so that these
two attributes are always documented during a declaration.

3.2 Nontype Function Template Parameters
You can also define nontype parameters for function templates. For example, the
following function template defines a group of functions for which a certain
value can be added: Click here to view code image
basics/addvalue.hpp
template
T addValue (T x)
{
return x + Val;
}

These kinds of functions can be useful if functions or operations are used as
parameters. For example, if you use the C++ standard library you can pass an
instantiation of this function template to add a value to each element of a
collection: Click here to view code image
std::transform (source.begin(), source.end(), //start and end of
source
dest.begin(), //start of destination
addValue<5,int>); // operation

The last argument instantiates the function template addValue<>() to add 5
to a passed int value. The resulting function is called for each element in the
source collection source, while it is translated into the destination collection
dest.
Note that you have to specify the argument int for the template parameter T
of addValue<>(). Deduction only works for immediate calls and
std::transform() need a complete type to deduce the type of its fourth
parameter. There is no support to substitute/deduce only some template
parameters and the see, what could fit, and deduce the remaining parameters.
Again, you can also specify that a template parameter is deduced from the
previous parameter. For example, to derive the return type from the passed

nontype: Click here to view code image
template
T foo();

or to ensure that the passed value has the same type as the passed type: Click
here to view code image
template
T bar();

3.3 Restrictions for Nontype Template Parameters
Note that nontype template parameters carry some restrictions. In general, they
can be only constant integral values (including enumerations), pointers to
objects/functions/members, lvalue references to objects or functions, or
std::nullptr_t (the type of nullptr).
Floating-point numbers and class-type objects are not allowed as nontype
template parameters: Click here to view code image
template // ERROR: floating-point values are not
double process (double v) // allowed as template parameters
{
return v * VAT;
}
template // ERROR: class-type objects are not
class MyClass { // allowed as template parameters
…
};

When passing template arguments to pointers or references, the objects must not
be string literals, temporaries, or data members and other subobjects. Because
these restrictions were relaxed with each and every C++ version before C++17,
additional constraints apply: • In C++11, the objects also had to have external
linkage.
• In C++14, the objects also had to have external or internal linkage.
Thus, the following is not possible: Click here to view code image
template
class MyClass {
…
};
MyClass<"hello"> x; //ERROR: string literal "hello" not allowed

However there are workarounds (again depending on the C++ version): Click
here to view code image
extern char const s03[] = "hi"; // external linkage
char const s11[] = "hi"; // internal linkage
int main()
{
Message m03;
Message m11;
static char const
Message m17;
}

// OK
// OK
s17[]
// OK

(all versions)
since C++11
= "hi"; // no linkage
since C++17

In all three cases a constant character array is initialized by "hello" and this
object is used as a template parameter declared with char const*. This is
valid in all C++ versions if the object has external linkage (s03), in C++11 and
C++14 also if it has internal linkage (s11), and since C++17 if it has no linkage
at all.
See Section 12.3.3 on page 194 for a detailed discussion and Section 17.2 on
page 354 for a discussion of possible future changes in this area.

Avoiding Invalid Expressions
Arguments for nontype template parameters might be any compile-time
expressions. For example: Click here to view code image
template
class C;
…
C c; However, note that if operator>
is used in the expression, you have to put the whole expression into
parentheses so that the nested > ends the argument list: Click here
to view code image
C<42, sizeof(int) > 4> c; // ERROR: first > ends the template
argument list
C<42, (sizeof(int) > 4)> c; // OK

3.4 Template Parameter Type auto
Since C++17, you can define a nontype template parameter to generically accept
any type that is allowed for a nontype parameter. Using this feature, we can

provide an even more generic stack class with fixed size: Click here to view
code image
basics/stackauto.hpp
#include 
#include 
template
class Stack {
public:
using size_type = decltype(Maxsize);
private:
std::array elems; // elements
size_type numElems; // current number of elements
public:
Stack(); // constructor
void push(T const& elem); // push element
void pop(); // pop element
T const& top() const; // return top element
bool empty() const { //return whether the stack is empty
return numElems == 0;
}
size_type size() const { //return current number of elements
return numElems;
}
};
// constructor
template
Stack::Stack ()
: numElems(0) //start with no elements
{
// nothing else to do
}
template
void Stack::push (T const& elem)
{
assert(numElems < Maxsize);
elems[numElems] = elem; // append element
++numElems; // increment number of elements
}
template
void Stack::pop ()
{
assert(!elems.empty());
--numElems; // decrement number of elements
}

template
T const& Stack::top () const
{
assert(!elems.empty());
return elems[numElems-1]; // return last element
}

By defining Click here to view code image
template
class Stack {
…
};

by using the placeholder type auto, you define Maxsize to be a value of a
type not specified yet. It might be any type that is allowed to be a nontype
template parameter type.
Internally you can use both the value: Click here to view code image
std::array elems; // elements

and its type:
Click here to view code image
using size_type = decltype(Maxsize); which is then, for example,
used as return type of the size() member function: Click here to view
code image
size_type size() const { //return current number of elements
return numElems;
}

Since C++14, you could also just use auto here as return type to let the
compiler find out the return type: Click here to view code image
auto size() const { //return current number of elements
return numElems;
}

With this class declaration the type of the number of elements is defined by the
type used for the number of elements, when using a stack: Click here to view
code image
basics/stackauto.cpp
#include 
#include 
#include "stackauto.hpp"
int main()
{

Stack int20Stack; // stack of up to 20 ints
Stack stringStack; // stack of up to 40 strings
// manipulate stack of up to 20 ints
int20Stack.push(7);
std::cout << int20Stack.top() << ’\n’;
auto size1 = int20Stack.size();
// manipulate stack of up to 40 strings
stringStack.push("hello");
std::cout << stringStack.top() << ’\n’;
auto size2 = stringStack.size();
if (!std::is_same_v) {
std::cout << "size types differ" << ’\n’;
}
}

With
Click here to view code image
Stack int20Stack; // stack of up to 20 ints

the internal size type is unsigned int, because 20u is passed.
With
Click here to view code image
Stack stringStack; // stack of up to 40 strings

the internal size type is int, because 40 is passed.
size() for the two stacks will have different return types, so that after Click
here to view code image
auto size1 = int20Stack.size();
…
auto size2 = stringStack.size(); the types of size1 and size2 differ.
By using the standard type trait std::is_same (see Section D.3.3 on
page 726) and decltype, we can check that: Click here to view code
image
if (!std::is_same::value) {
std::cout << "size types differ" << ’\n’;
}

Thus, the output will be: size types differ
Since C++17, for traits returning values, you can also use the suffix _v and skip
::value (see Section 5.6 on page 83 for details): Click here to view code
image
if (!std::is_same_v) {

std::cout << "size types differ" << ’\n’;
}

Note that other constraints on the type of nontype template parameters remain in
effect. Especially, the restrictions about possible types for nontype template
arguments discussed in Section 3.3 on page 49 still apply. For example: Click
here to view code image
Stack sd; // ERROR: Floating-point nontype argument

And, because you can also pass strings as constant arrays (since C++17 even
static locally declared; see Section 3.3 on page 49), the following is possible:
basics/message.cpp
Click here to view code image
#include 
template // take value of any possible nontype parameter
(since C++17)
class Message {
public:
void print() {
std::cout << T << ’\n’;
}
};
int main()
{
Message<42> msg1;
msg1.print(); // initialize with int 42 and print that value
static char const s[] = "hello";
Message msg2; // initialize with char const[6] "hello"
msg2.print(); // and print that value
}

Note also that even template is possible, which
allows instantiation of N as a reference: Click here to view code image
template
class C {
…
};
int i;
C<(i)> x; // N is int&

See Section 15.10.1 on page 296 for details.

3.5 Summary
• Templates can have template parameters that are values rather than types.
• You cannot use floating-point numbers or class-type objects as arguments for
nontype template parameters. For pointers/references to string literals,
temporaries, and subobjects, restrictions apply.
• Using auto enables templates to have nontype template parameters that are
values of generic types.

Chapter 4
Variadic Templates
Since C++11, templates can have parameters that accept a variable number of
template arguments. This feature allows the use of templates in places where you
have to pass an arbitrary number of arguments of arbitrary types. A typical
application is to pass an arbitrary number of parameters of arbitrary type through
a class or framework. Another application is to provide generic code to process
any number of parameters of any type.

4.1 Variadic Templates
Template parameters can be defined to accept an unbounded number of template
arguments. Templates with this ability are called variadic templates.

4.1.1 Variadic Templates by Example
For example, you can use the following code to call print() for a variable
number of arguments of different types: Click here to view code image
basics/varprint1.hpp
#include 
void print ()
{
}
template
void print (T firstArg, Types… args)
{
std::cout << firstArg << ’\n’; //print first argument
print(args…); // call print() for remaining arguments
}

If one or more arguments are passed, the function template is used, which by
specifying the first argument separately allows printing of the first argument
before recursively calling print() for the remaining arguments. These
remaining arguments named args are a function parameter pack: Click here to
view code image
void print (T firstArg, Types… args) using different “Types”
specified by a template parameter pack: Click here to view code image
template To end the recursion, the
nontemplate overload of print() is provided, which is issued when the
parameter pack is empty.

For example, a call such as Click here to view code image
std::string s("world");
print (7.5, "hello", s); would output the following: Click here to
view code image
7.5
hello
world

The reason is that the call first expands to Click here to view code image
print (7.5, "hello", s); with

• firstArg having the value 7.5 so that type T is a double and • args
being a variadic template argument having the values "hello" of type char
const* and "world" of type std::string.
After printing 7.5 as firstArg, it calls print() again for the remaining
arguments, which then expands to: Click here to view code image
print ("hello", s); with

• firstArg having the value "hello" so that type T is a char const*
here and • args being a variadic template argument having the value of type
std::string.
After printing "hello" as firstArg, it calls print() again for the
remaining arguments, which then expands to: Click here to view code image
print (s); with

• firstArg having the value "world" so that type T is a std::string
now and • args being an empty variadic template argument having no value.
Thus, after printing "world" as firstArg, we calls print() with no
arguments, which results in calling the nontemplate overload of print() doing
nothing.

4.1.2 Overloading Variadic and Nonvariadic
Templates
Note that you can also implement the example above as follows: Click here to
view code image
basics/varprint2.hpp
#include 
template
void print (T arg)
{
std::cout << arg << ’\n’; //print passed argument
}
template
void print (T firstArg, Types… args)
{
print(firstArg); // call print() for the first argument
print(args…); // call print() for remaining arguments
}

That is, if two function templates only differ by a trailing parameter pack, the
function template without the trailing parameter pack is preferred.1 Section C.3.1
on page 688 explains the more general overload resolution rule that applies here.

4.1.3 Operator sizeof…
C++11 also introduced a new form of the sizeof operator for variadic
templates: sizeof…. It expands to the number of elements a parameter pack
contains. Thus, Click here to view code image
template
void print (T firstArg, Types… args)
{
std::cout << sizeof…(Types) << ’\n’; //print number of remaining
types
std::cout << sizeof…(args) << ’\n’; //print number of remaining args
…
}

twice prints the number of remaining arguments after the first argument passed
to print(). As you can see, you can call sizeof… for both template

parameter packs and function parameter packs.
This might lead us to think we can skip the function for the end of the
recursion by not calling it in case there are no more arguments: Click here to
view code image
template
void print (T firstArg, Types… args)
{
std::cout << firstArg << ’\n’;
if (sizeof…(args) > 0) { //error if sizeof…(args)==0
print(args…); // and no print() for no arguments declared
}
}

However, this approach doesn’t work because in general both branches of all if
statements in function templates are instantiated. Whether the instantiated code
is useful is a run-time decision, while the instantiation of the call is a compiletime decision. For this reason, if you call the print() function template for
one (last) argument, the statement with the call of print(args…) still is
instantiated for no argument, and if there is no function print() for no
arguments provided, this is an error.
However, note that since C++17, a compile-time if is available, which
achieves what was expected here with a slightly different syntax. This will be
discussed in Section 8.5 on page 134.

4.2 Fold Expressions
Since C++17, there is a feature to compute the result of using a binary operator
over all the arguments of a parameter pack (with an optional initial value).
For example, the following function returns the sum of all passed arguments:
Click here to view code image
template
auto foldSum (T… s) {
return (… + s); // ((s1 + s2) + s3) …
}

If the parameter pack is empty, the expression is usually ill-formed (with the
exception that for operator && the value is true, for operator || the value is
false, and for the comma operator the value for an empty parameter pack is
void()).
Table 4.1 lists the possible fold expressions.

Fold Expression

Evaluation

( … op pack )

((( pack1 op pack2 ) op pack3 ) … op packN )

( pack op … )

( pack1 op ( … ( packN-1 op packN )))

( init op … op pack )

((( init op pack1 ) op pack2 ) … op packN )

( pack op … op init )

( pack1 op ( … ( packN op init )))

Table 4.1. Fold Expressions (since C++17)
You can use almost all binary operators for fold expressions (see Section
12.4.6 on page 208 for details). For example, you can use a fold expression to
traverse a path in a binary tree using operator ->*: Click here to view code
image
basics/foldtraverse.cpp
// define binary tree structure and traverse helpers:
struct Node {
int value;
Node* left;
Node* right;
Node(int i=0) : value(i), left(nullptr), right(nullptr) {
}
…
};
auto left = &Node::left;
auto right = &Node::right;
// traverse tree, using fold expression:
template
Node* traverse (T np, TP… paths) {
return (np ->* … ->* paths); // np ->* paths1 ->* paths2 …
}
int main()
{
// init binary tree structure:
Node* root = new Node{0};
root->left = new Node{1};
root->left->right = new Node{2};
…
// traverse binary tree:
Node* node = traverse(root, left, right);
…
}

Here,
(np ->* … ->* paths)

uses a fold expression to traverse the variadic elements of paths from np.
With such a fold expression using an initializer, we might think about
simplifying the variadic template to print all arguments, introduced above: Click
here to view code image
template
void print (Types const&… args)
{
(std::cout << … << args) << ’\n’;
}

However, note that in this case no whitespace separates all the elements from the
parameter pack. To do that, you need an additional class template, which ensures
that any output of any argument is extended by a space:
basics/addspace.hpp
Click here to view code image
template
class AddSpace
{
private:
T const& ref; // refer to argument passed in constructor
public:
AddSpace(T const& r): ref(r) {
}
friend std::ostream& operator<< (std::ostream& os, AddSpace s) {
return os << s.ref <<’’; // output passed argument and a space
}
};
template
void print (Args… args) {
( std::cout << … << AddSpace(args) ) << ’\n’;
}

Note that the expression AddSpace(args) uses class template argument
deduction (see Section 2.9 on page 40) to have the effect of AddSpace
(args), which for each argument creates an AddSpace object that refers to
the passed argument and adds a space when it is used in output expressions.
See Section 12.4.6 on page 207 for details about fold expressions.

4.3 Application of Variadic Templates
Variadic templates play an important role when implementing generic libraries,
such as the C++ standard library.
One typical application is the forwarding of a variadic number of arguments
of arbitrary type. For example, we use this feature when: • Passing arguments to
the constructor of a new heap object owned by a shared pointer: Click here to
view code image
// create shared pointer to complex initialized by 4.2 and
7.7:
auto sp = std::make_shared>(4.2, 7.7);

• Passing arguments to a thread, which is started by the library: Click here to
view code image
std::thread t (foo, 42, "hello"); //call foo(42,"hello") in a
separate thread

• Passing arguments to the constructor of a new element pushed into a vector:
Click here to view code image
std::vector v;
…
v.emplace("Tim", "Jovi", 1962); //insert a Customer initialized by
three arguments

Usually, the arguments are “perfectly forwarded” with move semantics (see
Section 6.1 on page 91), so that the corresponding declarations are, for example:
Click here to view code image
namespace std {
template shared_ptr
make_shared(Args&&… args);
class thread {
public:
template
explicit thread(F&& f, Args&&… args);
…
};
template>
class vector {
public:
template reference emplace_back(Args&&… args);
…
};
}

Note also that the same rules apply to variadic function template parameters as
for ordinary parameters. For example, if passed by value, arguments are copied
and decay (e.g., arrays become pointers), while if passed by reference,
parameters refer to the original parameter and don’t decay: Click here to view
code image
// args are copies with decayed types:
template void foo (Args… args);
// args are nondecayed references to passed objects:
template void bar (Args const&… args);

4.4 Variadic Class Templates and Variadic
Expressions
Besides the examples above, parameter packs can appear in additional places,
including, for example, expressions, class templates, using declarations, and
even deduction guides. Section 12.4.2 on page 202 has a complete list.

4.4.1 Variadic Expressions
You can do more than just forward all the parameters. You can compute with
them, which means to compute with all the parameters in a parameter pack.
For example, the following function doubles each parameter of the parameter
pack args and passes each doubled argument to print(): Click here to view
code image
template
void printDoubled (T const&… args)
{
print (args + args…);
}

If, for example, you call Click here to view code image
printDoubled(7.5, std::string("hello"), std::complex(4,2));

the function has the following effect (except for any constructor side effects):
Click here to view code image
print(7.5 + 7.5,
std::string("hello") + std::string("hello"),
std::complex(4,2) + std::complex(4,2); If you just want

to add 1 to each argument, note that the dots from the ellipsis may
not directly follow a numeric literal: Click here to view code image
template
void addOne (T const&… args)
{
print (args + 1…); // ERROR: 1… is a literal with too many decimal
points
print (args + 1 …); // OK
print ((args + 1)…); // OK
}

Compile-time expressions can include template parameter packs in the same
way. For example, the following function template returns whether the types of
all the arguments are the same: Click here to view code image
template
constexpr bool isHomogeneous (T1, TN…)
{
return (std::is_same::value && …); // since C++17
}

This is an application of fold expressions (see Section 4.2 on page 58): For Click
here to view code image
isHomogeneous(43, -1, "hello")

the expression for the return value expands to Click here to view code image
std::is_same::value && std::is_same::value

and yields false, while Click here to view code image
isHomogeneous("hello", "", "world", "!") yields true because all
passed arguments are deduced to be char const* (note that the
argument types decay because the call arguments are passed by value).

4.4.2 Variadic Indices
As another example, the following function uses a variadic list of indices to
access the corresponding element of the passed first argument: Click here to
view code image
template
void printElems (C const& coll, Idx… idx)
{
print (coll[idx]…);
}

That is, when calling Click here to view code image

std::vector coll = {"good", "times", "say", "bye"};
printElems(coll,2,0,3); the effect is to call Click here to view code
image
print (coll[2], coll[0], coll[3]);

You can also declare nontype template parameters to be parameter packs. For
example: Click here to view code image
template
void printIdx (C const& coll)
{
print(coll[Idx]…);
}

allows you to call Click here to view code image
std::vector coll = {"good", "times", "say", "bye"};
printIdx<2,0,3>(coll);

which has the same effect as the previous example.

4.4.3 Variadic Class Templates
Variadic templates can also be class templates. An important example is a class
where an arbitrary number of template parameters specify the types of
corresponding members: Click here to view code image
template
class Tuple;
Tuple t; // t can hold integer, string, and
character

This will be discussed in Chapter 25.
Another example is to be able to specify the possible types objects can have:
Click here to view code image
template
class Variant; Variant v; // v can hold
integer, string, or character

This will be discussed in Chapter 26.
You can also define a class that as a type represents a list of indices: Click
here to view code image
// type for arbitrary number of indices:
template
struct Indices {

};

This can be used to define a function that calls print() for the elements of a
std::array or std::tuple using the compile-time access with get<>()
for the given indices: Click here to view code image
template
void printByIdx(T t, Indices)
{
print(std::get(t)…);
}

This template can be used as follows: Click here to view code image
std::array arr = {"Hello", "my", "new", "!",
"World"}; printByIdx(arr, Indices<0, 4, 3>()); or as follows:
Click here to view code image
auto t = std::make_tuple(12, "monkeys", 2.0);
printByIdx(t, Indices<0, 1, 2>());

This is a first step towards meta-programming, which will be discussed in
Section 8.1 on page 123 and Chapter 23.

4.4.4 Variadic Deduction Guides
Even deduction guides (see Section 2.9 on page 42) can be variadic. For
example, the C++ standard library defines the following deduction guide for
std::arrays: Click here to view code image
namespace std {
template array(T, U…)
-> array && …), T>,
(1 + sizeof…(U))>;
}

An initialization such as std::array a{42,45,77};
deduces T in the guide to the type of the element, and the various U… types to the
types of the subsequent elements. The total number of elements is therefore 1 +
sizeof…(U): Click here to view code image
std::array a{42,45,77}; The std::enable_if<> expression for
the first array parameter is a fold expression that (as introduced as
isHomogeneous() in Section 4.4.1 on page 62) expands to: Click here
to view code image
is_same_v && is_same_v && is_same_v …

If the result is not true (i.e., not all the element types are the same), the
deduction guide is discarded and the overall deduction fails. This way, the
standard library ensures that all elements must have the same type for the
deduction guide to succeed.

4.4.5 Variadic Base Classes and using
Finally, consider the following example: Click here to view code image
basics/varusing.cpp
#include 
#include 
class Customer
{
private:
std::string name;
public:
Customer(std::string const& n) : name(n) { }
std::string getName() const { return name; }
};
struct CustomerEq {
bool operator() (Customer const& c1, Customer const& c2) const {
return c1.getName() == c2.getName();
}
};
struct CustomerHash {
std::size_t operator() (Customer const& c) const {
return std::hash()(c.getName());
}
};
// define class that combines operator() for variadic base classes:
template
struct Overloader : Bases…
{
using Bases::operator()…; // OK since C++17
};
int main()
{
// combine hasher and equality for customers in one type:
using CustomerOP = Overloader;
std::unordered_set coll1;

std::unordered_set coll2;
…
}

Here, we first define a class Customer and independent function objects to
hash and compare Customer objects. With Click here to view code image
template
struct Overloader : Bases…
{
using Bases::operator()…; // OK since C++17
};

we can define a class derived from a variadic number of base classes that brings
in the operator() declarations from each of those base classes. With Click
here to view code image
using CustomerOP = Overloader; we use this
feature to derive CustomerOP from CustomerHash and CustomerEq and
enable both implementations of operator() in the derived class.

See Section 26.4 on page 611 for another application of this technique.

4.5 Summary
• By using parameter packs, templates can be defined for an arbitrary number of
template parameters of arbitrary type.
• To process the parameters, you need recursion and/or a matching nonvariadic
function.
• Operator sizeof… yields the number of arguments provided for a parameter
pack.
• A typical application of variadic templates is forwarding an arbitrary number of
arguments of arbitrary type.
• By using fold expressions, you can apply operators to all arguments of a
parameter pack.
1 Initially, in C++11 and C++14 this was an ambiguity, which was fixed later
(see [CoreIssue1395]), but all compilers handle it this way in all versions.

Chapter 5
Tricky Basics
This chapter covers some further basic aspects of templates that are relevant to
the practical use of templates: an additional use of the typename keyword,
defining member functions and nested classes as templates, template template
parameters, zero initialization, and some details about using string literals as
arguments for function templates. These aspects can be tricky at times, but every
day-to-day programmer should have heard of them.

5.1 Keyword typename
The keyword typename was introduced during the standardization of C++ to
clarify that an identifier inside a template is a type. Consider the following
example: Click here to view code image
template
class MyClass {
public:
…
void foo() {
typename T::SubType* ptr;
}
};

Here, the second typename is used to clarify that SubType is a type defined
within class T. Thus, ptr is a pointer to the type T::SubType.
Without typename, SubType would be assumed to be a nontype member
(e.g., a static data member or an enumerator constant). As a result, the
expression T::SubType* ptr
would be a multiplication of the static SubType member of class T with ptr,
which is not an error, because for some instantiations of MyClass<> this could
be valid code.
In general, typename has to be used whenever a name that depends on a
template parameter is a type. This is discussed in detail in Section 13.3.2 on page

228.
One application of typename is the declaration to iterators of standard
containers in generic code: Click here to view code image
basics/printcoll.hpp
#include 
// print elements of an STL container
template
void printcoll (T const& coll)
{
typename T::const_iterator pos; // iterator to iterate over coll
typename T::const_iterator end(coll.end()); // end position
for (pos=coll.begin(); pos!=end; ++pos) {
std::cout << *pos << ’ ’;
}
std::cout << ’\n’;
}

In this function template, the call parameter is an standard container of type T.
To iterate over all elements of the container, the iterator type of the container is
used, which is declared as type const_iterator inside each standard
container class: Click here to view code image
class stlcontainer {
public:
using iterator = …; // iterator for read/write access
using const_iterator = …; // iterator for read access
…
};

Thus, to access type const_iterator of template type T, you have to
qualify it with a leading typename: Click here to view code image
typename T::const_iterator pos; See Section 13.3.2 on page 228 for
more details about the need for typename until C++17. Note that C++20
will probably remove the need for typename in many common cases (see
Section 17.1 on page 354 for details).

5.2 Zero Initialization
For fundamental types such as int, double, or pointer types, there is no
default constructor that initializes them with a useful default value. Instead, any
noninitialized local variable has an undefined value: Click here to view code

image
void foo()
{
int x; // x has undefined value
int* ptr; // ptr points to anywhere (instead of nowhere)
}

Now if you write templates and want to have variables of a template type
initialized by a default value, you have the problem that a simple definition
doesn’t do this for built-in types: Click here to view code image
template
void foo()
{
T x; // x has undefined value if T is built-in type
}

For this reason, it is possible to call explicitly a default constructor for built-in
types that initializes them with zero (or false for bool or nullptr for
pointers). As a consequence, you can ensure proper initialization even for builtin types by writing the following: Click here to view code image
template
void foo()
{
T x{}; // x is zero (or false) if T is a built-in type
}

This way of initialization is called value initialization, which means to either call
a provided constructor or zero initialize an object. This even works if the
constructor is explicit.
Before C++11, the syntax to ensure proper initialization was Click here to
view code image
T x = T(); // x is zero (or false) if T is a built-in type

Prior to C++17, this mechanism (which is still supported) only worked if the
constructor selected for the copy-initialization is not explicit. In C++17,
mandatory copy elision avoids that limitation and either syntax can work, but the
braced initialized notation can use an initializer-list constructor1 if no default
constructor is available.
To ensure that a member of a class template, for which the type is
parameterized, gets initialized, you can define a default constructor that uses a
braced initializer to initialize the member: Click here to view code image
template
class MyClass {

private:
T x;
public:
MyClass() : x{} { // ensures that x is initialized even for built-in
types
}
…
};

The pre-C++11 syntax
Click here to view code image
MyClass() : x() { //ensures that x is initialized even for built-in
types
}

also still works.
Since C++11, you can also provide a default initialization for a nonstatic
member, so that the following is also possible: Click here to view code image
template
class MyClass {
private:
T x{}; // zero-initialize x unless otherwise specified
…
};

However, note that default arguments cannot use that syntax. For example, Click
here to view code image
template
void foo(T p{}) { //ERROR
…
}

Instead, we have to write:
Click here to view code image
template
void foo(T p = T{}) { //OK (must use T() before C++11)
…
}

5.3 Using this->
For class templates with base classes that depend on template parameters, using
a name x by itself is not always equivalent to this->x, even though a member
x is inherited. For example: Click here to view code image

template
class Base {
public:
void bar();
};
template
class Derived : Base {
public:
void foo() {
bar(); // calls external bar() or error
}
};

In this example, for resolving the symbol bar inside foo(), bar() defined in
Base is never considered. Therefore, either you have an error, or another
bar() (such as a global bar()) is called.
We discuss this issue in Section 13.4.2 on page 237 in detail. For the moment,
as a rule of thumb, we recommend that you always qualify any symbol that is
declared in a base that is somehow dependent on a template parameter with
this-> or Base::.

5.4 Templates for Raw Arrays and String Literals
When passing raw arrays or string literals to templates, some care has to be
taken. First, if the template parameters are declared as references, the arguments
don’t decay. That is, a passed argument of "hello" has type char
const[6]. This can become a problem if raw arrays or string arguments of
different length are passed because the types differ. Only when passing the
argument by value, the types decay, so that string literals are converted to type
char const*. This is discussed in detail in Chapter 7.
Note that you can also provide templates that specifically deal with raw arrays
or string literals. For example: Click here to view code image
basics/lessarray.hpp
template bool less (T(&a)[N], T(&b)[M])
{
for (int i = 0; i() is instantiated with T being
int, N being 3, and M being 5.

You can also use this template for string literals: Click here to view code
image
std::cout << less("ab","abc") << ’\n’; In this case, less<>() is
instantiated with T being char const, N being 3 and M being 4.

If you only want to provide a function template for string literals (and other
char arrays), you can do this as follows: Click here to view code image
basics/lessstring.hpp
template
bool less (char const(&a)[N], char const(&b)[M])
{
for (int i = 0; i
template
struct MyClass; // primary template
template
struct MyClass // partial specialization for arrays of known
bounds
{
static void print() { std::cout << "print() for T[" << SZ << "]\n"; }
};

template
struct MyClass // partial spec. for references to arrays of
known bounds
{
static void print() { std::cout << "print() for T(&)[" << SZ << "]\n";
}
};
template
struct MyClass // partial specialization for arrays of unknown
bounds
{
static void print() { std::cout << "print() for T[]\n"; }
};
template
struct MyClass // partial spec. for references to arrays of
unknown bounds
{
static void print() { std::cout << "print() for T(&)[]\n"; }
};
template
struct MyClass // partial specialization for pointers
{
static void print() { std::cout << "print() for T*\n"; }
};

Here, the class template MyClass<> is specialized for various types: arrays of
known and unknown bound, references to arrays of known and unknown
bounds, and pointers. Each case is different and can occur when using arrays:
Click here to view code image
basics/arrays.cpp
#include "arrays.hpp"
template
void foo(int a1[7], int a2[], // pointers by language rules
int (&a3)[42], // reference to array of known bound
int (&x0)[], // reference to array of unknown bound
T1 x1, // passing by value decays
T2& x2, T3&& x3) // passing by reference
{
MyClass::print(); // uses MyClass
MyClass::print(); // uses MyClass
MyClass::print(); // uses MyClass
MyClass::print(); // uses MyClass
MyClass::print(); // uses MyClass
MyClass::print(); // uses MyClass

MyClass::print(); // uses MyClass
}
int main()
{
int a[42];
MyClass::print(); // uses MyClass
extern int x[]; // forward declare array
MyClass::print(); // uses MyClass
foo(a, a, a, x, x, x, x);
}
int x[] = {0, 8, 15}; // define forward-declared array

Note that a call parameter declared as an array (with or without length) by
language rules really has a pointer type. Note also that templates for arrays of
unknown bounds can be used for an incomplete type such as extern int i[]; And
when this is passed by reference, it becomes a int(&)[], which can also be
used as a template parameter.2
See Section 19.3.1 on page 401 for another example using the different array
types in generic code.

5.5 Member Templates
Class members can also be templates. This is possible for both nested classes
and member functions. The application and advantage of this ability can again
be demonstrated with the Stack<> class template. Normally you can assign
stacks to each other only when they have the same type, which implies that the
elements have the same type. However, you can’t assign a stack with elements of
any other type, even if there is an implicit type conversion for the element types
defined: Click here to view code image
Stack intStack1, intStack2; // stacks for ints
Stack floatStack; // stack for floats
…
intStack1 = intStack2; // OK: stacks have same type
floatStack = intStack1; // ERROR: stacks have different types

The default assignment operator requires that both sides of the assignment
operator have the same type, which is not the case if stacks have different
element types.

By defining an assignment operator as a template, however, you can enable
the assignment of stacks with elements for which an appropriate type conversion
is defined. To do this you have to declare Stack<> as follows: Click here to
view code image
basics/stack5decl.hpp
template
class Stack {
private:
std::deque elems; // elements
public:
void push(T const&); // push element
void pop(); // pop element
T const& top() const; // return top element
bool empty() const { // return whether the stack is empty
return elems.empty();
}
// assign stack of elements of type T2
template
Stack& operator= (Stack const&);
};

The following two changes have been made: 1. We added a declaration of an
assignment operator for stacks of elements of another type T2.
2. The stack now uses a std::deque<> as an internal container for the
elements. Again, this is a consequence of the implementation of the new
assignment operator.
The implementation of the new assignment operator looks like this:3
Click here to view code image

basics/stack5assign.hpp
template
template
Stack& Stack::operator= (Stack const& op2)
{
Stack tmp(op2); // create a copy of the assigned stack
elems.clear(); // remove existing elements
while (!tmp.empty()) { // copy all elements
elems.push_front(tmp.top());
tmp.pop();
}
return *this;

}

First let’s look at the syntax to define a member template. Inside the template
with template parameter T, an inner template with template parameter T2 is
defined: Click here to view code image
template
template
…

Inside the member function, you may expect simply to access all necessary data
for the assigned stack op2. However, this stack has a different type (if you
instantiate a class template for two different argument types, you get two
different class types), so you are restricted to using the public interface. It
follows that the only way to access the elements is by calling top(). However,
each element has to become a top element, then. Thus, a copy of op2 must first
be made, so that the elements are taken from that copy by calling pop().
Because top() returns the last element pushed onto the stack, we might prefer
to use a container that supports the insertion of elements at the other end of the
collection. For this reason, we use a std::deque<>, which provides
push_front() to put an element on the other side of the collection.
To get access to all the members of op2 you can declare that all other stack
instances are friends: Click here to view code image
basics/stack6decl.hpp
template
class Stack {
private:
std::deque elems; // elements
public:
void push(T const&); // push element
void pop(); // pop element
T const& top() const; // return top element
bool empty() const { // return whether the stack is empty
return elems.empty();
}

// assign stack of elements of type T2
template
Stack& operator= (Stack const&);
// to get access to private members of Stack for any type T2:
template friend class Stack;
};

As you can see, because the name of the template parameter is not used, you can
omit it: Click here to view code image
template friend class Stack; Now, the following
implementation of the template assignment operator is possible: Click
here to view code image

basics/stack6assign.hpp
template
template
Stack& Stack::operator= (Stack const& op2)
{
elems.clear(); // remove existing elements
elems.insert(elems.begin(), // insert at the beginning
op2.elems.begin(), // all elements from op2
op2.elems.end());
return *this;
}

Whatever your implementation is, having this member template, you can now
assign a stack of ints to a stack of floats: Click here to view code image
Stack intStack; // stack for ints
Stack floatStack; // stack for floats
…
floatStack = intStack; // OK: stacks have different types,
// but int converts to float

Of course, this assignment does not change the type of the stack and its
elements. After the assignment, the elements of the floatStack are still
floats and therefore top() still returns a float.
It may appear that this function would disable type checking such that you
could assign a stack with elements of any type, but this is not the case. The
necessary type checking occurs when the element of the (copy of the) source
stack is moved to the destination stack: elems.push_front(tmp.top());
If, for example, a stack of strings gets assigned to a stack of floats, the
compilation of this line results in an error message stating that the string returned
by tmp.top() cannot be passed as an argument to elems.push_front()
(the message varies depending on the compiler, but this is the gist of what is
meant): Click here to view code image
Stack stringStack; // stack of strings
Stack floatStack; // stack of floats
…
floatStack = stringStack; // ERROR: std::string doesn’t convert to
float

Again, you could change the implementation to parameterize the internal
container type: Click here to view code image
basics/stack7decl.hpp
template>
class Stack {
private:
Cont elems; // elements
public:
void push(T const&); // push element
void pop(); // pop element
T const& top() const; // return top element
bool empty() const { // return whether the stack is empty
return elems.empty();
}
// assign stack of elements of type T2
template
Stack& operator= (Stack const&);
// to get access to private members of Stack for any type T2:
template friend class Stack;
};

Then the template assignment operator is implemented like this: Click here to
view code image
basics/stack7assign.hpp
template
template
Stack&
Stack::operator= (Stack const& op2)
{
elems.clear(); // remove existing elements
elems.insert(elems.begin(), // insert at the beginning
op2.elems.begin(), // all elements from op2
op2.elems.end());
return *this;
}

Remember, for class templates, only those member functions that are called are
instantiated. Thus, if you avoid assigning a stack with elements of a different
type, you could even use a vector as an internal container: Click here to view
code image

// stack for ints using a vector as an internal container
Stack> vStack;
…
vStack.push(42); vStack.push(7);
std::cout << vStack.top() << ’\n’; Because the assignment operator
template isn’t necessary, no error message of a missing member
function push_front() occurs and the program is fine.

For the complete implementation of the last example, see all the files with a
name that starts with stack7 in the subdirectory basics.
Specialization of Member Function Templates
Member function templates can also be partially or fully specialized. For
example, for the following class: Click here to view code image
basics/boolstring.hpp
class BoolString {
private:
std::string value;
public:
BoolString (std::string const& s)
: value(s) {
}
template
T get() const { // get value (converted to T)
return value;
}
};

you can provide a full specialization for the member function template as
follows: Click here to view code image
basics/boolstringgetbool.hpp
// full specialization for BoolString::getValue<>() for bool
template<>
inline bool BoolString::get() const {
return value == "true" || value == "1" || value == "on";
}

Note that you don’t need and also can’t declare the specializations; you only
define them. Because it is a full specialization and it is in a header file you have
to declare it with inline to avoid errors if the definition is included by
different translation units.

You can use class and the full specialization as follows: Click here to view
code image
std::cout << std::boolalpha;
BoolString s1("hello");
std::cout << s1.get() << ’\n’; //prints hello
std::cout << s1.get() << ’\n’; //prints false
BoolString s2("on");
std::cout << s2.get() << ’\n’; //prints true

Special Member Function Templates
Template member functions can be used wherever special member functions
allow copying or moving objects. Similar to assignment operators as defined
above, they can also be constructors. However, note that template constructors or
template assignment operators don’t replace predefined constructors or
assignment operators. Member templates don’t count as the special member
functions that copy or move objects. In this example, for assignments of stacks
of the same type, the default assignment operator is still called.
This effect can be good and bad: • It can happen that a template constructor or
assignment operator is a better match than the predefined copy/move constructor
or assignment operator, although a template version is provided for initialization
of other types only. See Section 6.2 on page 95 for details.
• It is not easy to “templify” a copy/move constructor, for example, to be able to
constrain its existence. See Section 6.4 on page 102 for details.

5.5.1 The .template Construct
Sometimes, it is necessary to explicitly qualify template arguments when calling
a member template. In that case, you have to use the template keyword to
ensure that a < is the beginning of the template argument list. Consider the
following example using the standard bitset type: Click here to view code
image
template
void printBitset (std::bitset const& bs) {
std::cout << bs.template to_string,
std::allocator>();
}

For the bitset bs we call the member function template to_string(), while
explicitly specifying the string type details. Without that extra use of

.template, the compiler does not know that the less-than token (<) that
follows is not really less-than but the beginning of a template argument list. Note
that this is a problem only if the construct before the period depends on a
template parameter. In our example, the parameter bs depends on the template
parameter N.
The .template notation (and similar notations such as ->template and
::template) should be used only inside templates and only if they follow
something that depends on a template parameter. See Section 13.3.3 on page 230
for details.

5.5.2 Generic Lambdas and Member Templates
Note that generic lambdas, introduced with C++14, are shortcuts for member
templates. A simple lambda computing the “sum” of two arguments of arbitrary
types: Click here to view code image
[] (auto x, auto y) {
return x + y;
}

is a shortcut for a default-constructed object of the following class: Click here to
view code image
class SomeCompilerSpecificName {
public:
SomeCompilerSpecificName(); // constructor only callable by compiler
template
auto operator() (T1 x, T2 y) const {
return x + y;
}
};

See Section 15.10.6 on page 309 for details.

5.6 Variable Templates
Since C++14, variables also can be parameterized by a specific type. Such a
thing is called a variable template.4
For example, you can use the following code to define the value of ˇ while
still not defining the type of the value: Click here to view code image
template

constexpr T pi{3.1415926535897932385}; Note that, as for all
templates, this declaration may not occur inside functions or block
scope.

To use a variable template, you have to specify its type. For example, the
following code uses two different variables of the scope where pi<> is
declared: Click here to view code image
std::cout
std::cout
templates
view code

<< pi << ’\n’;
<< pi << ’\n’; You can also declare variable
that are used in different translation units: Click here to
image

//== header.hpp:
template T val{}; // zero initialized value
//== translation unit 1:
#include "header.hpp"
int main()
{
val = 42;
print();
}
//== translation unit 2:
#include "header.hpp"
void print()
{
std::cout << val << ’\n’; // OK: prints 42
}

Variable templates can also have default template arguments: Click here to view
code image
template
constexpr T pi = T{3.1415926535897932385}; You can use the default or
any other type: Click here to view code image
std::cout << pi<> << ’\n’; //outputs a long double
std::cout << pi << ’\n’; //outputs a float

However, note that you always have to specify the angle brackets. Just using pi
is an error: Click here to view code image
std::cout << pi << ’\n’; //ERROR

Variable templates can also be parameterized by nontype parameters, which also
may be used to parameterize the initializer. For example: Click here to view code
image
#include 

#include 
template
std::array arr{}; // array with N elements, zero-initialized
template
constexpr decltype(N) dval = N; // type of dval depends on passed
value
int main()
{
std::cout << dval<’c’> << ’\n’; // N has value ’c’ of type char
arr<10>[0] = 42; // sets first element of global arr
for (std::size_t i=0; i.size(); ++i) { // uses values set in
arr
std::cout << arr<10>[i] << ’\n’;
}
}

Again, note that even when the initialization of and iteration over arr happens
in different translation units the same variable std::array arr
of global scope is still used.
Variable Templates for Data Members
A useful application of variable templates is to define variables that represent
members of class templates. For example, if a class template is defined as
follows: Click here to view code image
template
class MyClass {
public:
static constexpr int max = 1000;
};

which allows you to define different values for different specializations of
MyClass<>, then you can define Click here to view code image
template
int myMax = MyClass::max; so that application programmers can just
write Click here to view code image
auto i = myMax; instead of
Click here to view code image
auto i = MyClass::max; This means, for a standard class
such as Click here to view code image
namespace std {
template class numeric_limits {
public:

…
static constexpr bool is_signed = false;
…
};
}

you can define Click here to view code image
template
constexpr bool isSigned = std::numeric_limits::is_signed; to be
able to write
isSigned instead of
Click here to view code image
std::numeric_limits::is_signed

Type Traits Suffix _v
Since C++17, the standard library uses the technique of variable templates to
define shortcuts for all type traits in the standard library that yield a (Boolean)
value. For example, to be able to write Click here to view code image
std::is_const_v // since C++17

instead of
Click here to view code image
std::is_const::value //since C++11

the standard library defines
Click here to view code image
namespace std {
template constexpr bool is_const_v = is_const::value;
}

5.7 Template Template Parameters
It can be useful to allow a template parameter itself to be a class template.
Again, our stack class template can be used as an example.
To use a different internal container for stacks, the application programmer
has to specify the element type twice. Thus, to specify the type of the internal
container, you have to pass the type of the container and the type of its elements
again: Click here to view code image
Stack> vStack; // integer stack that uses a

vector

Using template template parameters allows you to declare the Stack class
template by specifying the type of the container without respecifying the type of
its elements: Click here to view code image
Stack vStack; // integer stack that uses a vector

To do this, you must specify the second template parameter as a template
template parameter. In principle, this looks as follows:5
Click here to view code image

basics/stack8decl.hpp
template class Cont = std::deque>
class Stack {
private:
Cont elems; // elements
public:
void push(T const&); // push element
void pop(); // pop element
T const& top() const; // return top element
bool empty() const { // return whether the stack is empty
return elems.empty();
}
…
};

The difference is that the second template parameter is declared as being a class
template: Click here to view code image
template class Cont The default value has changed from
std::deque to std::deque. This parameter has to be a class
template, which is instantiated for the type that is passed as the
first template parameter: Cont elems;

This use of the first template parameter for the instantiation of the second
template parameter is particular to this example. In general, you can instantiate a
template template parameter with any type inside a class template.
As usual, instead of typename you could use the keyword class for
template parameters. Before C++11, Cont could only be substituted by the
name of a class template.
Click here to view code image
template class Cont = std::deque>

class Stack { //OK
…
};

Since C++11, we can also substitute Cont with the name of an alias template,
but it wasn’t until C++17 that a corresponding change was made to permit the
use of the keyword typename instead of class to declare a template template
parameter: Click here to view code image
template typename Cont = std::deque>
class Stack { //ERROR before C++17
…
};

Those two variants mean exactly the same thing: Using class instead of
typename does not prevent us from specifying an alias template as the
argument corresponding to the Cont parameter.
Because the template parameter of the template template parameter is not
used, it is customary to omit its name (unless it provides useful documentation):
Click here to view code image
template class Cont = std::deque>
class Stack {
…
};

Member functions must be modified accordingly. Thus, you have to specify the
second template parameter as the template template parameter. The same applies
to the implementation of the member function. The push() member function,
for example, is implemented as follows: Click here to view code image
template class Cont>
void Stack::push (T const& elem)
{
elems.push_back(elem); // append copy of passed elem
}

Note that while template template parameters are placeholders for class or alias
templates, there is no corresponding placeholder for function or variable
templates.
Template Template Argument Matching
If you try to use the new version of Stack, you may get an error message
saying that the default value std::deque is not compatible with the template

template parameter Cont. The problem is that prior to C++17 a template
template argument had to be a template with parameters that exactly match the
parameters of the template template parameter it substitutes, with some
exceptions related to variadic template parameters (see Section 12.3.4 on page
197). Default template arguments of template template arguments were not
considered, so that a match couldn’t be achieved by leaving out arguments that
have default values (in C++17, default arguments are considered).
The pre-C++17 problem in this example is that the std::deque template of
the standard library has more than one parameter: The second parameter (which
describes an allocator) has a default value, but prior to C++17 this was not
considered when matching std::deque to the Cont parameter.
There is a workaround, however. We can rewrite the class declaration so that
the Cont parameter expects containers with two template parameters: Click here
to view code image
template>
class Cont = std::deque>
class Stack {
private:
Cont elems; // elements
…
};

Again, we could omit Alloc because it is not used.
The final version of our Stack template (including member templates for
assignments of stacks of different element types) now looks as follows: Click
here to view code image
basics/stack9.hpp
#include 
#include 
#include 
template>
class Cont = std::deque>
class Stack {
private:
Cont elems; // elements
public:
void push(T const&); // push element

void pop(); // pop element
T const& top() const; // return top element
bool empty() const { // return whether the stack is empty
return elems.empty();
}
// assign stack of elements of type T2
template
>class Cont2>
Stack& operator= (Stack const&);
// to get access to private members of any Stack with elements of type
T2:
templateclass>
friend class Stack;
};
template class Cont>
void Stack::push (T const& elem)
{
elems.push_back(elem); // append copy of passed elem
}
template class Cont>
void Stack::pop ()
{
assert(!elems.empty());
elems.pop_back(); // remove last element
}
template class Cont>
T const& Stack::top () const
{
assert(!elems.empty());
return elems.back(); // return copy of last element
}
template class Cont>
template class Cont2>
Stack&
Stack::operator= (Stack const& op2)
{
elems.clear(); // remove existing elements
elems.insert(elems.begin(), // insert at the beginning
op2.elems.begin(), // all elements from op2
op2.elems.end());
return *this;
}

Note again that to get access to all the members of op2 we declare that all other

stack instances are friends (omitting the names of the template parameters):
Click here to view code image
templateclass>
friend class Stack; Still, not all standard container templates can
be used for Cont parameter. For example, std::array will not work
because it includes a nontype template parameter for the array length
that has no match in our template template parameter declaration.

The following program uses all features of this final version: Click here to
view code image
basics/stack9test.cpp
#include "stack9.hpp"
#include 
#include 
int main()
{
Stack iStack; // stack of ints
Stack fStack; // stack of floats
// manipulate int stack
iStack.push(1);
iStack.push(2);
std::cout << "iStack.top(): " << iStack.top() << ’\n’;
// manipulate float stack:
fStack.push(3.3);
std::cout << "fStack.top(): " << fStack.top() << ’\n’;
// assign stack of different type and manipulate again
fStack = iStack;
fStack.push(4.4);
std::cout << "fStack.top(): " << fStack.top() << ’\n’;
// stack for doubless using a vector as an internal container
Stack vStack;
vStack.push(5.5);
vStack.push(6.6);
std::cout << "vStack.top(): " << vStack.top() << ’\n’;
vStack = fStack;
std::cout << "vStack: ";
while (! vStack.empty()) {
std::cout << vStack.top() << ’ ’;
vStack.pop();
}
std::cout << ’\n’;
}

The program has the following output: Click here to view code image
iStack.top():
fStack.top():
fStack.top():
vStack.top():
vStack: 4.4 2

2
3.3
4.4
6.6
1

For further discussion and examples of template template parameters, see
Section 12.2.3 on page 187, Section 12.3.4 on page 197, and Section 19.2.2 on
page 398.

5.8 Summary
• To access a type name that depends on a template parameter, you have to
qualify the name with a leading typename.
• To access members of bases classes that depend on template parameters, you
have to qualify the access by this-> or their class name.
• Nested classes and member functions can also be templates. One application is
the ability to implement generic operations with internal type conversions.
• Template versions of constructors or assignment operators don’t replace
predefined constructors or assignment operators.
• By using braced initialization or explicitly calling a default constructor, you
can ensure that variables and members of templates are initialized with a
default value even if they are instantiated with a built-in type.
• You can provide specific templates for raw arrays, which can also be applicable
to string literals.
• When passing raw arrays or string literals, arguments decay (perform an arrayto-pointer conversion) during argument deduction if and only if the parameter
is not a reference.
• You can define variable templates (since C++14).
• You can also use class templates as template parameters, as template template
parameters.
• Template template arguments must usually match their parameters exactly.
1

That is, a constructor with a parameter of type
std::initializer_list, for some type X.
2 Parameters of type X (&)[]—for some arbitrary type X—have become
valid only in C++17, through the resolution of Core issue 393. However,

many compilers accepted such parameters in earlier versions of the language.
This is a basic implementation to demonstrate the template features. Issues
like proper exception handling are certainly missing.
4 Yes, we have very similar terms for very different things: A variable template
is a variable that is a template (variable is a noun here). A variadic template is
a template for a variadic number of template parameters (variadic is an
adjective here).
5 Before C++17, there is an issue with this version that we explain in a minute.
However, this affects only the default value std::deque. Thus, we can
illustrate the general features of template template parameters with this default
value before we discuss how to deal with it before C++17.
3

Chapter 6
Move Semantics and enable_if<>
One of the most prominent features C++11 introduced was move semantics. You
can use it to optimize copying and assignments by moving (“stealing”) internal
resources from a source object to a destination object instead of copying those
contents. This can be done provided the source no longer needs its internal value
or state (because it is about to be discarded).
Move semantics has a significant influence on the design of templates, and
special rules were introduced to support move semantics in generic code. This
chapter introduces these features.

6.1 Perfect Forwarding
Suppose you want to write generic code that forwards the basic property of
passed arguments: • Modifyable objects should be forwarded so that they still
can be modified.
• Constant objects should be forwarded as read-only objects.
• Movable objects (objects we can “steal” from because they are about to expire)
should be forwarded as movable objects.
To achieve this functionality without templates, we have to program all three
cases. For example, to forward a call of f() to a corresponding function g():
Click here to view code image
basics/move1.cpp
#include 
#include 
class X {
…
};
void g (X&) {
std::cout << "g() for variable\n";
}

void g (X const&) {
std::cout << "g() for constant\n";
}
void g (X&&) {
std::cout << "g() for movable object\n";
}
// let f() forward argument val to g():
void f (X& val) {
g(val); // val is non-const lvalue => calls g(X&)
}
void f (X const& val) {
g(val); // val is const lvalue => calls g(X const&)
}
void f (X&& val) {
g(std::move(val)); // val is non-const lvalue => needs std::move() to
call g(X&&)
}
int main()
{
X v; // create variable
X const c; // create constant
f(v); // f() for nonconstant object calls f(X&) =>
f(c); // f() for constant object calls f(X const&)
const&)
f(X()); // f() for temporary calls f(X&&) => calls
f(std::move(v)); // f() for movable variable calls
g(X&&)
}

calls g(X&)
=> calls g(X
g(X&&)
f(X&&) => calls

Here, we see three different implementations of f() forwarding its argument to
g(): Click here to view code image
void f (X& val) {
g(val); // val is non-const lvalue => calls g(X&)
}
void f (X const& val) {
g(val); // val is const lvalue => calls g(X const&)
}
void f (X&& val) {
g(std::move(val)); // val is non-const lvalue => needs std::move() to
call g(X&&)
}

Note that the code for movable objects (via an rvalue reference) differs from the
other code: It needs a std::move() because according to language rules,
move semantics is not passed through.1 Although val in the third f() is
declared as rvalue reference its value category when used as expression is a

nonconstant lvalue (see Appendix B) and behaves as val in the first f().
Without the move(), g(X&) for nonconstant lvalues instead of g(&&) would
be called.
If we want to combine all three cases in generic code, we have a problem:
Click here to view code image
template
void f (T val) {
g(T);
}

works for the first two cases, but not for the (third) case where movable objects
are passed.
C++11 for this reason introduces special rules for perfect forwarding
parameters. The idiomatic code pattern to achieve this is as follows: Click here
to view code image
template
void f (T&& val) {
g(std::forward(val)); // perfect forward val to g()
}

Note that std::move() has no template parameter and “triggers” move
semantics for the passed argument, while std::forward<>() “forwards”
potential move semantic depending on a passed template argument.
Don’t assume that T&& for a template parameter T behaves as X&& for a
specific type X. Different rules apply! However, syntactically they look identical:
• X&& for a specific type X declares a parameter to be an rvalue reference. It can
only be bound to a movable object (a prvalue, such as a temporary object, and an
xvalue, such as an object passed with std::move(); see Appendix B for
details). It is always mutable and you can always “steal” its value.2
• T&& for a template parameter T declares a forwarding reference (also called
universal reference).3 It can be bound to a mutable, immutable (i.e., const),
or movable object. Inside the function definition, the parameter may be
mutable, immutable, or refer to a value you can “steal” the internals from.
Note that T must really be the name of a template parameter. Depending on a
template parameter is not sufficient. For a template parameter T, a declaration
such as typename T::iterator&& is just an rvalue reference, not a
forwarding reference.
So, the whole program to perfect forward arguments will look as follows:
Click here to view code image

basics/move2.cpp
#include 
#include 
class X {
…
};
void g (X&) {
std::cout << "g()
}
void g (X const&)
std::cout << "g()
}
void g (X&&) {
std::cout << "g()
}

for variable\n";
{
for constant\n";

for movable object\n";

// let f() perfect forward argument val to g():
template
void f (T&& val) {
g(std::forward(val)); // call the right g() for any passed argument
val
}
int main()
{
X v; // create variable
X const c; // create constant
f(v); // f() for variable calls f(X&) => calls g(X&)
f(c); // f() for constant calls f(X const&) => calls g(X const&)
f(X()); // f() for temporary calls f(X&&) => calls g(X&&)
f(std::move(v)); // f() for move-enabled variable calls f(X&&) =>
calls g(X&&)
}

Of course, perfect forwarding can also be used with variadic templates (see
Section 4.3 on page 60 for some examples). See Section 15.6.3 on page 280 for
details of perfect forwarding.

6.2 Special Member Function Templates
Member function templates can also be used as special member functions,
including as a constructor, which, however, might lead to surprising behavior.
Consider the following example: Click here to view code image

basics/specialmemtmpl1.cpp
#include 
#include 
#include 
class Person
{
private:
std::string name;
public:
// constructor for passed initial name:
explicit Person(std::string const& n) : name(n) {
std::cout << "copying string-CONSTR for ’" << name << "’\n";
}
explicit Person(std::string&& n) : name(std::move(n)) {
std::cout << "moving string-CONSTR for ’" << name << "’\n";
}
// copy and move constructor:
Person (Person const& p) : name(p.name) {
std::cout << "COPY-CONSTR Person ’" << name << "’\n";
}
Person (Person&& p) : name(std::move(p.name)) {
std::cout << "MOVE-CONSTR Person ’" << name << "’\n";
}
};
int main()
{
std::string s = "sname";
Person p1(s); // init with string object => calls copying stringCONSTR
Person p2("tmp"); // init with string literal => calls moving stringCONSTR
Person p3(p1); // copy Person => calls COPY-CONSTR
Person p4(std::move(p1)); // move Person => calls MOVE-CONST
}

Here, we have a class Person with a string member name for which we
provide initializing constructors. To support move semantics, we overload the
constructor taking a std::string: • We provide a version for string object
the caller still needs, for which name is initialized by a copy of the passed
argument: Click here to view code image
Person(std::string const& n) : name(n) {
std::cout << "copying string-CONSTR for ’" << name << "’\n";
}

• We provide a version for movable string object, for which we call
std::move() to “steal” the value from: Click here to view code image

Person(std::string&& n) : name(std::move(n)) {
std::cout << "moving string-CONSTR for ’" << name << "’\n";
}

As expected, the first is called for passed string objects that are in use (lvalues),
while the latter is called for movable objects (rvalues): Click here to view code
image
std::string s = "sname";
Person p1(s); // init with string object => calls copying stringCONSTR
Person p2("tmp"); // init with string literal => calls moving stringCONSTR

Besides these constructors, the example has specific implementations for the
copy and move constructor to see when a Person as a whole is copied/moved:
Click here to view code image
Person p3(p1); // copy Person => calls COPY-CONSTR
Person p4(std::move(p1)); // move Person => calls MOVE-CONSTR

Now let’s replace the two string constructors with one generic constructor
perfect forwarding the passed argument to the member name: Click here to view
code image
basics/specialmemtmpl2.hpp
#include 
#include 
#include 
class Person
{
private:
std::string name;
public:
// generic constructor for passed initial name:
template
explicit Person(STR&& n) : name(std::forward(n)) {
std::cout << "TMPL-CONSTR for ’" << name << "’\n";
}
// copy and move constructor:
Person (Person const& p) : name(p.name) {
std::cout << "COPY-CONSTR Person ’" << name << "’\n";
}
Person (Person&& p) : name(std::move(p.name)) {
std::cout << "MOVE-CONSTR Person ’" << name << "’\n";
}
};

Construction with passed string works fine, as expected: Click here to view code
image
std::string s = "sname";
Person p1(s); // init with string object => calls TMPL-CONSTR
Person p2("tmp"); //init with string literal => calls TMPL-CONSTR

Note how the construction of p2 does not create a temporary string in this case:
The parameter STR is deduced to be of type char const[4]. Applying
std::forward to the pointer parameter of the constructor has not
much of an effect, and the name member is thus constructed from a nullterminated string.
But when we attempt to call the copy constructor, we get an error: Click here
to view code image
Person p3(p1); // ERROR

while initializing a new Person by a movable object still works fine: Click here
to view code image
Person p4(std::move(p1)); // OK: move Person => calls MOVE-CONST

Note that also copying a constant Person works fine: Click here to view code
image
Person const p2c("ctmp"); //init constant object with string literal
Person p3c(p2c); // OK: copy constant Person => calls COPY-CONSTR

The problem is that, according to the overload resolution rules of C++ (see
Section 16.2.4 on page 333), for a nonconstant lvalue Person p the member
template Click here to view code image
template
Person(STR&& n)

is a better match than the (usually predefined) copy constructor: Click here to
view code image
Person (Person const& p) STR is just substituted with Person&, while
for the copy constructor a conversion to const is necessary.

You might think about solving this by also providing a nonconstant copy
constructor: Person (Person& p) However, that is only a partial solution because
for objects of a derived class, the member template is still a better match. What
you really want is to disable the member template for the case that the passed
argument is a Person or an expression that can be converted to a Person.
This can be done by using std::enable_if<>, which is introduced in the
next section.

6.3 Disable Templates with enable_if<>
Since C++11, the C++ standard library provides a helper template
std::enable_if<> to ignore function templates under certain compile-time
conditions.
For example, if a function template foo<>() is defined as follows: Click
here to view code image
template
typename std::enable_if<(sizeof(T) > 4)>::type
foo() {
}

this definition of foo<>() is ignored if sizeof(T) > 4 yields false.4 If
sizeof(T) > 4 yields true, the function template instance expands to void
foo() {
}
That is, std::enable_if<> is a type trait that evaluates a given compiletime expression passed as its (first) template argument and behaves as follows: •
If the expression yields true, its type member type yields a type: – The type
is void if no second template argument is passed.
– Otherwise, the type is the second template argument type.
• If the expression yields false, the member type is not defined. Due to a
template feature called SFINAE (substitution failure is not an error), which is
introduced later (see Section 8.4 on page 129), this has the effect that the
function template with the enable_if expression is ignored.
As for all type traits yielding a type since C++14, there is a corresponding alias
template std::enable_if_t<>, which allows you to skip typename and
::type (see Section 2.8 on page 40 for details). Thus, since C++14 you can
write Click here to view code image
template
std::enable_if_t<(sizeof(T) > 4)>
foo() {
}

If a second argument is passed to enable_if<> or enable_if_t<>: Click
here to view code image
template
std::enable_if_t<(sizeof(T) > 4), T>
foo() {
return T();

}

the enable_if construct expands to this second argument if the expression
yields true. So, if MyType is the concrete type passed or deduced as T, whose
size is larger than 4, the effect is MyType foo();
Note that having the enable_if expression in the middle of a declaration is
pretty clumsy. For this reason, the common way to use std::enable_if<>
is to use an additional function template argument with a default value: Click
here to view code image
template 4)>>
void foo() {
}

which expands to
Click here to view code image
template
void foo() {
}

if sizeof(T) > 4.
If that is still too clumsy, and you want to make the requirement/constraint
more explicit, you can define your own name for it using an alias template:5
Click here to view code image
template
using EnableIfSizeGreater4 = std::enable_if_t<(sizeof(T) > 4)>;
template>
void foo() {
}

See Section 20.3 on page 469 for a discussion of how std::enable_if is
implemented.

6.4 Using enable_if<>
We can use enable_if<> to solve our problem with the constructor template
introduced in Section 6.2 on page 95.
The problem we have to solve is to disable the declaration of the template
constructor Click here to view code image

template
Person(STR&& n);

if the passed argument STR has the right type (i.e., is a std::string or a type
convertible to std::string).
For this, we use another standard type trait,
std::is_convertible. With C++17, the corresponding
declaration looks as follows: Click here to view code image
template>>
Person(STR&& n);

If type STR is convertible to type std::string, the whole declaration
expands to Click here to view code image
template
Person(STR&& n);

If type STR is not convertible to type std::string, the whole function
template is ignored.6
Again, we can define our own name for the constraint by using an alias
template: Click here to view code image
template
using EnableIfString = std::enable_if_t<
std::is_convertible_v>;
…
template>
Person(STR&& n);

Thus, the whole class Person should look as follows: Click here to view code
image
basics/specialmemtmpl3.hpp
#include
#include
#include
#include






template
using EnableIfString = std::enable_if_t<
std::is_convertible_v>;
class Person
{
private:

std::string name;
public:
// generic constructor for passed initial name:
template>
explicit Person(STR&& n)
: name(std::forward(n)) {
std::cout << "TMPL-CONSTR for ’" << name << "’\n";
}
// copy and move constructor:
Person (Person const& p) : name(p.name) {
std::cout << "COPY-CONSTR Person ’" << name << "’\n";
}
Person (Person&& p) : name(std::move(p.name)) {
std::cout << "MOVE-CONSTR Person ’" << name << "’\n";
}
};

Now, all calls behave as expected: Click here to view code image
basics/specialmemtmpl3.cpp
#include "specialmemtmpl3.hpp"
int main()
{
std::string s = "sname";
Person p1(s); // init with string object => calls TMPL-CONSTR
Person p2("tmp"); // init with string literal => calls TMPL-CONSTR
Person p3(p1); // OK => calls COPY-CONSTR
Person p4(std::move(p1)); // OK => calls MOVE-CONST
}

Note again that in C++14, we have to declare the alias template as follows,
because the _v version is not defined for type traits that yield a value: Click here
to view code image
template
using EnableIfString = std::enable_if_t<
std::is_convertible::value>;

And in C++11, we have to declare the special member template as follows,
because as written the _t version is not defined for type traits that yield a type:
Click here to view code image
template
using EnableIfString
= typename std::enable_if::value
>::type;

But that’s all hidden now in the definition of EnableIfString<>.

Note also that there is an alternative to using std::is_convertible<>
because it requires that the types are implicitly convertible. By using
std::is_constructible<>, we also allow explicit conversions to be used
for the initialization. However, the order of the arguments is the opposite is this
case: Click here to view code image
template
using EnableIfString = std::enable_if_t<
std::is_constructible_v>;

See Section D.3.2 on page 719 for details about
std::is_constructible<> and Section D.3.3 on page 727 for details
about std::is_convertible<>. See Section D.6 on page 734 for details
and examples to apply enable_if<> on variadic templates.
Disabling Special Member Functions
Note that normally we can’t use enable_if<> to disable the predefined
copy/move constructors and/or assignment operators. The reason is that member
function templates never count as special member functions and are ignored
when, for example, a copy constructor is needed. Thus, with this declaration:
Click here to view code image
class C {
public:
template
C (T const&) {
std::cout << "tmpl copy constructor\n";
}
…
};

the predefined copy constructor is still used, when a copy of a C is requested:
Click here to view code image
C x;
C y{x}; // still uses the predefined copy constructor (not the member
template)

(There is really no way to use the member template because there is no way to
specify or deduce its template parameter T.) Deleting the predefined copy
constructor is no solution, because then the trial to copy a C results in an error.
There is a tricky solution, though:7 We can declare a copy constructor for
const volatile arguments and mark it “deleted” (i.e., define it with =
delete). Doing so prevents another copy constructor from being implicitly

declared. With that in place, we can define a constructor template that will be
preferred over the (deleted) copy constructor for nonvolatile types: Click here to
view code image
class C
{
public:
…
// user-define the predefined copy constructor as deleted
// (with conversion to volatile to enable better matches)
C(C const volatile&) = delete;
// implement copy constructor template with better match:
template
C (T const&) {
std::cout << "tmpl copy constructor\n";
}
…
};

Now the template constructors are used even for “normal” copying: Click here to
view code image
C x;
C y{x}; // uses the member template

In such a template constructor we can then apply additional constraints with
enable_if<>. For example, to prevent being able to copy objects of a class
template C<> if the template parameter is an integral type, we can implement the
following: Click here to view code image
template
class C
{
public:
…
// user-define the predefined copy constructor as deleted
// (with conversion to volatile to enable better matches)
C(C const volatile&) = delete;
// if T is no integral type, provide copy constructor template with
better match:
template::value>>
C (C const&) {
…
}
…
};

6.5 Using Concepts to Simplify enable_if<>
Expressions
Even when using alias templates, the enable_if syntax is pretty clumsy,
because it uses a work-around: To get the desired effect, we add an additional
template parameter and “abuse” that parameter to provide a specific requirement
for the function template to be available at all. Code like this is hard to read and
makes the rest of the function template hard to understand.
In principle, we just need a language feature that allows us to formulate
requirements or constraints for a function in a way that causes the function to be
ignored if the requirements/constraints are not met.
This is an application of the long-awaited language feature concepts, which
allows us to formulate requirements/conditions for templates with its own simple
syntax. Unfortunately, although long discussed, concepts still did not become
part of the C++17 standard. Some compilers provide experimental support for
such a feature, however, and concepts will likely become part of the next
standard after C++17.
With concepts, as their use is proposed, we simply have to write the following:
Click here to view code image
template
requires std::is_convertible_v
Person(STR&& n) : name(std::forward(n)) {
…
}

We can even specify the requirement as a general concept Click here to view
code image
template
concept ConvertibleToString = std::is_convertible_v;
and formulate this concept as a requirement: Click here to view code
image
template
requires ConvertibleToString
Person(STR&& n) : name(std::forward(n)) {
…
}

This also can be formulated as follows: Click here to view code image
template
Person(STR&& n) : name(std::forward(n)) {
…
}

See Appendix E for a detailed discussion of concepts for C++.

6.6 Summary
• In templates, you can “perfectly” forward parameters by declaring them as
forwarding references (declared with a type formed with the name of a
template parameter followed by &&) and using std::forward<>() in the
forwarded call.
• When using perfect forwarding member function templates, they might match
better than the predefined special member function to copy or move objects.
• With std::enable_if<>, you can disable a function template when a
compile-time condition is false (the template is then ignored once that
condition has been determined).
• By using std::enable_if<> you can avoid problems when constructor
templates or assignment operator templates that can be called for single
arguments are a better match than implicitly generated special member
functions.
• You can templify (and apply enable_if<>) to special member functions by
deleting the predefined special member functions for const volatile.
• Concepts will allow us to use a more intuitive syntax for requirements on
function templates.
1 The fact that move semantics is not automatically passed through is
intentional and important. If it weren’t, we would lose the value of a movable
object the first time we use it in a function.
2 A type like X const&& is valid but provides no common semantics in
practice because “stealing” the internal representation of a movable object
requires modifying that object. It might be used, though, to force passing only
temporaries or objects marked with std::move() without being able to
modify them.
3 The term universal reference was coined by Scott Meyers as a common term
that could result in either an “lvalue reference” or an “rvalue reference.”
Because “universal” was, well, too universal, the C++17 standard introduced
the term forwarding reference, because the major reason to use such a
reference is to forward objects. However, note that it does not automatically
forward. The term does not describe what it is but what it is typically used for.
4 Don’t forget to place the condition into parentheses, because otherwise the >

in the condition would end the template argument list.
Thanks to Stephen C. Dewhurst for pointing that out.
6 If you wonder why we don’t instead check whether STR is “not convertible to
Person,” beware: We are defining a function that might allow us to convert a
string to a Person. So the constructor has to know whether it is enabled,
which depends on whether it is convertible, which depends on whether it is
enabled, and so on. Never use enable_if in places that impact the
condition used by enable_if. This is a logical error that compilers do not
necessarily detect.
7 Thanks to Peter Dimov for pointing out this technique.
5

Chapter 7
By Value or by Reference?
Since the beginning, C++ has provided call-by-value and call-by-reference, and
it is not always easy to decide which one to choose: Usually calling by reference
is cheaper for nontrivial objects but more complicated. C++11 added move
semantics to the mix, which means that we now have different ways to pass by
reference:1
1. X const& (constant lvalue reference): The parameter refers to the passed
object, without the ability to modify it.
2. X& (nonconstant lvalue reference): The parameter refers to the passed object,
with the ability to modify it.
3. X&& (rvalue reference): The parameter refers to the passed object, with move
semantics, meaning that you can modify or “steal” the value.
Deciding how to declare parameters with known concrete types is complicated
enough. In templates, types are not known, and therefore it becomes even harder
to decide which passing mechanism is appropriate.
Nevertheless, in Section 1.6.1 on page 20 we did recommend passing
parameters in function templates by value unless there are good reasons, such as
the following: • Copying is not possible.2
• Parameters are used to return data.
• Templates just forward the parameters to somewhere else by keeping all the
properties of the original arguments.
• There are significant performance improvements.
This chapter discusses the different approaches to declare parameters in
templates, motivating the general recommendation to pass by value, and
providing arguments for the reasons not to do so. It also discusses the tricky
problems you run into when dealing with string literals and other raw arrays.
When reading this chapter, it is helpful to be familiar with the terminology of
value categories (lvalue, rvalue, prvalue, xvalue, etc.), which is explained in
Appendix B.

7.1 Passing by Value
When passing arguments by value, each argument must in principle be copied.
Thus, each parameter becomes a copy of the passed argument. For classes, the
object created as a copy generally is initialized by the copy constructor.
Calling a copy constructor can become expensive. However, there are various
way to avoid expensive copying even when passing parameters by value: In fact,
compilers might optimize away copy operations copying objects and can become
cheap even for complex objects by using move semantics.
For example, let’s look at a simple function template implemented so that the
argument is passed by value: Click here to view code image
template
void printV (T arg) {
…
}

When calling this function template for an integer, the resulting code is Click
here to view code image
void printV (int arg) {
…
}

Parameter arg becomes a copy of any passed argument, whether it is an object
or a literal or a value returned by a function.
If we define a std::string and call our function template for it: std::string
s = "hi";
printV(s);
the template parameter T is instantiated as std::string so that we get Click
here to view code image
void printV (std::string arg)
{
…
}

Again, when passing the string, arg becomes a copy of s. This time the copy is
created by the copy constructor of the string class, which is a potentially
expensive operation, because in principle this copy operation creates a full or
“deep” copy so that the copy internally allocates its own memory to hold the
value.3
However, the potential copy constructor is not always called. Consider the
following: Click here to view code image

std::string returnString();
std::string s = "hi";
printV(s); //copy constructor
printV(std::string("hi")); //copying usually optimized away (if not,
move constructor)
printV(returnString()); // copying usually optimized away (if not,
move constructor)
printV(std::move(s)); // move constructor

In the first call we pass an lvalue, which means that the copy constructor is used.
However, in the second and third calls, when directly calling the function
template for prvalues (temporary objects created on the fly or returned by
another function; see Appendix B), compilers usually optimize passing the
argument so that no copying constructor is called at all. Note that since C++17,
this optimization is required. Before C++17, a compiler that doesn’t optimize the
copying away, must at least have to try to use move semantics, which usually
makes copying cheap. In the last call, when passing an xvalue (an existing
nonconstant object with std::move()), we force to call the move constructor
by signaling that we no longer need the value of s.
Thus, calling an implementation of printV() that declares the parameter to
be passed by value usually is only expensive if we pass an lvalue (an object we
created before and typically still use afterwards, as we didn’t use
std::move() to pass it). Unfortunately, this is a pretty common case. One
reason is that it is pretty common to create objects early to pass them later (after
some modifications) to other functions.
Passing by Value Decays
There is another property of passing by value we have to mention: When passing
arguments to a parameter by value, the type decays. This means that raw arrays
get converted to pointers and that qualifiers such as const and volatile are
removed (just like using the value as initializer for an object declared with
auto):4
Click here to view code image
template
void printV (T arg) {
…
}
Click here to view code image
std::string const c = "hi";
printV(c); // c decays so that arg has type std::string

printV("hi"); //decays to pointer so that arg has type char const*
int arr[4];
printV(arr); // decays to pointer so that arg has type char const*

Thus, when passing the string literal "hi", its type char const[3] decays
to char const* so that this is the deduced type of T. Thus, the template is
instantiated as follows: Click here to view code image
void printV (char const* arg)
{
…
}

This behavior is derived from C and has its benefits and drawbacks. Often it
simplifies the handling of passed string literals, but the drawback is that inside
printV() we can’t distinguish between passing a pointer to a single element
and passing a raw array. For this reason, we will discuss how to deal with string
literals and other raw arrays in Section 7.4 on page 115.

7.2 Passing by Reference
Now let’s discuss the different flavors of passing by reference. In all cases, no
copy gets created (because the parameter just refers to the passed argument).
Also, passing the argument never decays. However, sometimes passing is not
possible, and if passing is possible, there are cases in which the resulting type of
the parameter may cause problems.

7.2.1 Passing by Constant Reference
To avoid any (unnecessary) copying, when passing nontemporary objects, we
can use constant references. For example: Click here to view code image
template
void printR (T const& arg) {
…
}

With this declaration, passing an object never creates a copy (whether it’s cheap
or not): Click here to view code image
std::string returnString();

std::string s = "hi";
printR(s); // no copy
printR(std::string("hi")); // no copy
printR(returnString()); // no copy
printR(std::move(s)); // no copy

Even an int is passed by reference, which is a bit counterproductive but
shouldn’t matter that much. Thus: Click here to view code image
int i = 42;
printR(i); // passes reference instead of just copying i

results in printR() being instantiated as: Click here to view code image
void printR(int const& arg) {
…
}

Under the hood, passing an argument by reference is implemented by passing the
address of the argument. Addresses are encoded compactly, and therefore
transferring an address from the caller to the callee is efficient in itself. However,
passing an address can create uncertainties for the compiler when it compiles the
caller’s code: What is the callee doing with that address? In theory, the callee can
change all the values that are “reachable” through that address. That means, that
the compiler has to assume that all the values it may have cached (usually, in
machine registers) are invalid after the call. Reloading all those values can be
quite expensive. You may be thinking that we are passing by constant reference:
Cannot the compiler deduce from that that no change can happen?
Unfortunately, that is not the case because the caller may modify the referenced
object through its own, non-const reference.5
This bad news is moderated by inlining: If the compiler can expand the call
inline, it can reason about the caller and the callee together and in many cases
“see” that the address is not used for anything but passing the underlying value.
Function templates are often very short and therefore likely candidates for inline
expansion. However, if a template encapsulates a more complex algorithm,
inlining is less likely to happen.
Passing by Reference Does Not Decay
When passing arguments to parameters by reference, they do not decay. This
means that raw arrays are not converted to pointers and that qualifiers such as
const and volatile are not removed. However, because the call parameter
is declared as T const&, the template parameter T itself is not deduced as
const. For example: Click here to view code image

template
void printR (T const& arg) {
…
}
std::string const c = "hi";
printR(c); // T deduced as std::string, arg is std::string const&
printR("hi"); // T deduced as char[3], arg is char const(&)[3]
int arr[4];
printR(arr); // T deduced as int[4], arg is int const(&)[4]

Thus, local objects declared with type T in printR() are not constant.

7.2.2 Passing by Nonconstant Reference
When you want to return values through passed arguments (i.e., when you want
to use out or inout parameters), you have to use nonconstant references (unless
you prefer to pass them via pointers). Again, this means that when passing the
arguments, no copy gets created. The parameters of the called function template
just get direct access to the passed argument.
Consider the following:
Click here to view code image
template
void outR (T& arg) {
…
}

Note that calling outR() for a temporary (prvalue) or an existing object passed
with std::move() (xvalue) usually is not allowed: Click here to view code
image
std::string returnString();
std::string s = "hi";
outR(s); //OK: T deduced as std::string, arg is std::string&
outR(std::string("hi")); //ERROR: not allowed to pass a temporary
(prvalue)
outR(returnString()); // ERROR: not allowed to pass a temporary
(prvalue)
outR(std::move(s)); // ERROR: not allowed to pass an xvalue

You can pass raw arrays of nonconstant types, which again don’t decay: Click
here to view code image
int arr[4];
outR(arr); // OK: T deduced as int[4], arg is int(&)[4]

Thus, you can modify elements and, for example, deal with the size of the array.
For example: Click here to view code image
template
void outR (T& arg) {
if (std::is_array::value) {
std::cout << "got array of " << std::extent::value << " elems\n";
}
…
}

However, templates are a bit tricky here. If you pass a const argument, the
deduction might result in arg becoming a declaration of a constant reference,
which means that passing an rvalue is suddenly allowed, where an lvalue is
expected: Click here to view code image
std::string const c = "hi";
outR(c); // OK: T deduced as std::string const
outR(returnConstString()); // OK: same if returnConstString() returns
const string
outR(std::move(c)); // OK: T deduced as std::string const6
outR("hi"); // OK: T deduced as char const[3]

Of course, any attempt to modify the passed argument inside the function
template is an error in such cases. Passing a const object is possible in the call
expression itself, but when the function is fully instantiated (which may happen
later in the compilation process) any attempt to modify the value will trigger an
error (which, however, might happen deep inside the called template; see Section
9.4 on page 143).
If you want to disable passing constant objects to nonconstant references, you
can do the following: • Use a static assertion to trigger a compile-time error:
Click here to view code image
template
void outR (T& arg) {
static_assert(!std::is_const::value,
"out parameter of foo(T&) is const");
…
}

• Disable the template for this case either by using std::enable_if<> (see
Section 6.3 on page 98): Click here to view code image
template::value>
void outR (T& arg) {
…
}

or concepts once they are supported (see Section 6.5 on page 103 and
Appendix E): Click here to view code image
template
requires !std::is_const_v
void outR (T& arg) {
…
}

7.2.3 Passing by Forwarding Reference
One reason to use call-by-reference is to be able to perfect forward a parameter
(see Section 6.1 on page 91). But remember that when a forwarding reference is
used, which is defined as an rvalue reference of a template parameter, special
rules apply. Consider the following: Click here to view code image
template
void passR (T&& arg) { // arg declared as forwarding reference
…
}

You can pass everything to a forwarding reference and, as usual when passing by
reference, no copy gets created: Click here to view code image
std::string s = "hi";
passR(s); // OK: T deduced as std::string& (also the type of arg)
passR(std::string("hi")); // OK: T deduced as std::string, arg is
std::string&&
passR(returnString()); // OK: T deduced as std::string, arg is
std::string&&
passR(std::move(s)); // OK: T deduced as std::string, arg is
std::string&&
passR(arr); // OK: T deduced as int(&)[4] (also the type of arg)

However, the special rules for type deduction may result in some surprises: Click
here to view code image
std::string const c = "hi";
passR(c); //OK: T deduced as std::string const&
passR("hi"); //OK: T deduced as char const(&)[3] (also the type of
arg)
int arr[4];
passR("hi"); //OK: T deduced as int (&)[4] (also the type of arg)

In each of these cases, inside passR() the parameter arg has a type that
“knows” whether we passed an rvalue (to use move semantics) or a
constant/nonconstant lvalue. This is the only way to pass an argument, such that

it can be used to distinguish behavior for all of these three cases.
This gives the impression that declaring a parameter as a forwarding reference
is almost perfect. But beware, there is no free lunch.
For example, this is the only case where the template parameter T implicitly
can become a reference type. As a consequence, it might become an error to use
T to declare a local object without initialization: Click here to view code image
template
void passR(T&& arg) { // arg is a forwarding reference
T x; // for passed lvalues, x is a reference, which requires an
initializer
…
}
foo(42); // OK: T deduced as int
int i;
foo(i); // ERROR: T deduced as int&, which makes the declaration of x
in passR() invalid

See Section 15.6.2 on page 279 for further details about how you can deal with
this situation.

7.3 Using std::ref() and std::cref()
Since C++11, you can let the caller decide, for a function template argument,
whether to pass it by value or by reference. When a template is declared to take
arguments by value, the caller can use std::cref() and std::ref(),
declared in header file , to pass the argument by reference. For
example: Click here to view code image
template
void printT (T arg) {
…
}
std::string s = "hello";
printT(s); //pass s by reference
printT(std::cref(s)); // pass s “as if by reference”

However, note that std::cref() does not change the handling of parameters
in templates. Instead, it uses a trick: It wraps the passed argument s by an object
that acts like a reference. In fact, it creates an object of type
std::reference_wrapper<> referring to the original argument and

passes this object by value. The wrapper more or less supports only one
operation: an implicit type conversion back to the original type, yielding the
original object.7 So, whenever you have a valid operator for the passed object,
you can use the reference wrapper instead. For example: Click here to view code
image
basics/cref.cpp
#include  // for std::cref()
#include 
#include 
void printString(std::string const& s)
{
std::cout << s << ’\n’;
}
template
void printT (T arg)
{
printString(arg); // might convert arg back to std::string
}
int main()
{
std::string s = "hello";
printT(s); // print s passed by value
printT(std::cref(s)); // print s passed “as if by reference”
}

The last call passes by value an object of type
std::reference_wrapper to the parameter arg,
which then passes and therefore converts it back to its underlying type
std::string.
Note that the compiler has to know that an implicit conversion back to the
original type is necessary. For this reason, std::ref() and std::cref()
usually work fine only if you pass objects through generic code. For example,
directly trying to output the passed object of the generic type T will fail because
there is no output operator defined for std::reference_wrapper<>:
Click here to view code image
template
void printV (T arg) {
std::cout << arg << ’\n’;
}
…

std::string s = "hello";
printV(s); //OK
printV(std::cref(s)); // ERROR: no operator << for reference wrapper
defined

Also, the following fails because you can’t compare a reference wrapper with a
char const* or std::string: Click here to view code image
template
bool isless(T1 arg1, T2 arg2)
{
return arg1 < arg2;
}
…
std::string s = "hello";
if (isless(std::cref(s) < "world")) … //ERROR
if (isless(std::cref(s) < std::string("world"))) … //ERROR

It also doesn’t help to give arg1 and arg2 a common type T: Click here to
view code image
template
bool isless(T arg1, T arg2)
{
return arg1 < arg2;
}

because then the compiler gets conflicting types when trying to deduce T for
arg1 and arg2.
Thus, the effect of class std::reference_wrapper<> is to be able to
use a reference as a “first class object,” which you can copy and therefore pass
by value to function templates. You can also use it in classes, for example, to
hold references to objects in containers. But you always finally need a
conversion back to the underlying type.

7.4 Dealing with String Literals and Raw Arrays
So far, we have seen the different effects for templates parameters when using
string literals and raw arrays: • Call-by-value decays so that they become
pointers to the element type.
• Any form of call-by-reference does not decay so that the arguments become
references that still refer to arrays.
Both can be good and bad. When decaying arrays to pointers, you lose the ability
to distinguish between handling pointers to elements from handling passed

arrays. On the other hand, when dealing with parameters where string literals
may be passed, not decaying can become a problem, because string literals of
different size have different types. For example: Click here to view code image
template
void foo (T const& arg1, T const& arg2)
{
…
}
foo("hi", "guy"); //ERROR

Here, foo("hi","guy") fails to compile, because "hi" has type char
const[3], while "guy" has type char const[4], but the template
requires them to have the same type T. Only if the string literals were to have the
same length would such code compile. For this reason, it is strongly
recommended to use string literals of different lengths in test cases.
By declaring the function template foo() to pass the argument by value the
call is possible: Click here to view code image
template
void foo (T arg1, T arg2)
{
…
}
foo("hi", "guy"); //compiles, but …

But, that doesn’t mean that all problems are gone. Even worse, compile-time
problems may have become run-time problems. Consider the following code,
where we compare the passed argument using operator==: Click here to view
code image
template
void foo (T arg1, T arg2)
{
if (arg1 == arg2) { //OOPS: compares addresses of passed arrays
…
}
}
foo("hi", "guy"); //compiles, but …

As written, you have to know that you should interpret the passed character
pointers as strings. But that’s probably the case anyway, because the template
also has to deal with arguments coming from string literals that have been
decayed already (e.g., by coming from another function called by value or being
assigned to an object declared with auto).

Nevertheless, in many cases decaying is helpful, especially for checking
whether two objects (both passed as arguments or one passed as argument and
the other expecting the argument) have or convert to the same type. One typical
usage is perfect forwarding. But if you want to use perfect forwarding, you have
to declare the parameters as forwarding references. In those cases, you might
explicitly decay the arguments using the type trait std::decay<>(). See the
story of std::make_pair() in Section 7.6 on page 120 for a concrete
example.
Note that other type traits sometimes also implicitly decay, such as
std::common_type<>, which yields the common type of two passed
argument types (see Section 1.3.3 on page 12 and Section D.5 on page 732).

7.4.1 Special Implementations for String Literals and
Raw Arrays
You might have to distinguish your implementation according to whether a
pointer or an array was passed. This, of course, requires that a passed array
wasn’t decayed yet.
To distinguish these cases, you have to detect whether arrays are passed.
Basically, there are two options: • You can declare template parameters so that
they are only valid for arrays: Click here to view code image
template
void foo(T (&arg1)[L1], T (&arg2)[L2])
{
T* pa = arg1; // decay arg1
T* pb = arg2; // decay arg2
if (compareArrays(pa, L1, pb, L2)) {
…
}
}

Here, arg1 and arg2 have to be raw arrays of the same element type T but
with different sizes L1 and L2. However, note that you might need multiple
implementations to support the various forms of raw arrays (see Section 5.4 on
page 71).
• You can use type traits to detect whether an array (or a pointer) was passed:
Click here to view code image
template>>

void foo (T&& arg1, T&& arg2)
{
…
}

Due to these special handling, often the best way to deal with arrays in different
ways is simply to use different function names. Even better, of course, is to
ensure that the caller of a template uses std::vector or std::array. But
as long as string literals are raw arrays, we always have to take them into
account.

7.5 Dealing with Return Values
For return values, you can also decide between returning by value or by
reference. However, returning references is potentially a source of trouble,
because you refer to something that is out of your control. There are a few cases
where returning references is common programming practice: • Returning
elements of containers or strings (e.g., by operator[] or front()) •
Granting write access to class members • Returning objects for chained calls
(operator<< and operator>> for streams and operator= for class
objects in general) In addition, it is common to grant read access to members by
returning const references.
Note that all these cases may cause trouble if used improperly. For example:
Click here to view code image
std::string* s = new std::string("whatever");
auto& c = (*s)[0];
delete s;
std::cout << c; //run-time ERROR

Here, we obtained a reference to an element of a string, but by the time we use
that reference, the underlying string no longer exists (i.e., we created a dangling
reference), and we have undefined behavior. This example is somewhat
contrived (the experienced programmer is likely to notice the problem right
away), but things easily become less obvious. For example: Click here to view
code image
auto s = std::make_shared("whatever");
auto& c = (*s)[0];
s.reset();
std::cout << c; //run-time ERROR

We should therefore ensure that function templates return their result by value.

However, as discussed in this chapter, using a template parameter T is no
guarantee that it is not a reference, because T might sometimes implicitly be
deduced as a reference: Click here to view code image
template
T retR(T&& p) // p is a forwarding reference
{
return T{…}; // OOPS: returns by reference when called for lvalues
}

Even when T is a template parameter deduced from a call-by-value call, it might
become a reference type when explicitly specifying the template parameter to be
a reference: Click here to view code image
template
T retV(T p) //Note: T might become a reference
{
return T{…}; // OOPS: returns a reference if T is a reference
}
int x;
retV(x); // retT() instantiated for T as int&

To be safe, you have two options: • Use the type trait
std::remove_reference<> (see Section D.4 on page 729) to convert type
T to a nonreference: Click here to view code image
template
typename std::remove_reference::type retV(T p)
{
return T{…}; // always returns by value
}

Other traits, such as std::decay<> (see Section D.4 on page 731), may also
be useful here because they also implicitly remove references.
• Let the compiler deduce the return type by just declaring the return type to be
auto (since C++14; see Section 1.3.2 on page 11), because auto always
decays: Click here to view code image
template
auto retV(T p) // by-value return type deduced by compiler
{
return T{…}; // always returns by value
}

7.6 Recommended Template Parameter Declarations

As we learned in the previous sections, we have very different ways to declare
parameters that depend on template parameters: • Declare to pass the arguments
by value: This approach is simple, it decays string literals and raw arrays, but it
doesn’t provide the best performance for large objects. Still the caller can decide
to pass by reference using std::cref() and std::ref(), but the caller
must be careful that doing so is valid.
• Declare to pass the arguments by-reference: This approach often provides
better performance for somewhat large objects, especially when passing –
existing objects (lvalues) to lvalue references, – temporary objects (prvalues)
or objects marked as movable (xvalue) to rvalue references, – or both to
forwarding references.
Because in all these cases the arguments don’t decay, you may need special
care when passing string literals and other raw arrays. For forwarding
references, you also have to beware that with this approach template
parameters implicitly can deduce to reference types.
General Recommendations
With these options in mind, for function templates we recommend the following:
1. By default, declare parameters to be passed by value. This is simple and
usually works even with string literals. The performance is fine for small
arguments and for temporary or movable objects. The caller can sometimes use
std::ref() and std::cref() when passing existing large objects
(lvalues) to avoid expensive copying.
2. If there are good reasons, do otherwise: – If you need an out or inout
parameter, which returns a new object or allows to modify an argument to/for
the caller, pass the argument as a nonconstant reference (unless you prefer to
pass it via a pointer). However, you might consider disabling accidentally
accepting const objects as discussed in Section 7.2.2 on page 110.
– If a template is provided to forward an argument, use perfect forwarding.
That is, declare parameters to be forwarding references and use
std::forward<>() where appropriate. Consider using std::decay<>
or std::common_type<> to “harmonize” the different types of string
literals and raw arrays.
– If performance is key and it is expected that copying arguments is expensive,
use constant references. This, of course, does not apply if you need a local
copy anyway.
3. If you know better, don’t follow these recommendations. However, do not

make intuitive assumptions about performance. Even experts fail if they try.
Instead: Measure!
Don’t Be Over-Generic
Note that, in practice, function templates often are not for arbitrary types of
arguments. Instead, some constraints apply. For example, you may know that
only vectors of some type are passed. In this case, it is better not to declare such
a function too generically, because, as discussed, surprising side effects may
occur. Instead, use the following declaration: Click here to view code image
template
void printVector (std::vector const& v)
{
…
}

With this declaration of parameter v in printVector(), we can be sure that
the passed T can’t become a reference because vectors can’t use references as
element types. Also, it is pretty clear that passing a vector by value almost
always can become expensive because the copy constructor of
std::vector<> creates a copy of the elements. For this reason, it is probably
never useful to declare such a vector parameter to be passed by value. If we
declare parameter v just as having type T deciding, between call-by-value and
call-by-reference becomes less obvious.

The std::make_pair() Example
std::make_pair<>() is a good example to demonstrate the pitfalls of
deciding a parameter passing mechanism. It is a convenience function template
in the C++ standard library to create std::pair<> objects using type
deduction. Its declaration changed through different versions of the C++
standard: • In the first C++ standard, C++98, make_pair<>() was declared
inside namespace std to use call-by-reference to avoid unnecessary copying:
Click here to view code image
template
pair make_pair (T1 const& a, T2 const& b)
{
return pair(a,b);
}

This, however, almost immediately caused significant problems when using
pairs of string literals or raw arrays of different size.8
• As a consequence, with C++03 the function definition was changed to use callby-value: Click here to view code image
template
pair make_pair (T1 a, T2 b)
{
return pair(a,b);
}

As you can read in the rationale for the issue resolution, “it appeared that this
was a much smaller change to the standard than the other two suggestions,
and any efficiency concerns were more than offset by the advantages of the
solution.”
• However, with C++11, make_pair() had to support move semantics, so that
the arguments had to become forwarding references. For this reason, the
definition changed roughly again as follows: Click here to view code image
template
constexpr pair::type, typename decay::type>
make_pair (T1&& a, T2&& b)
{
return pair::type,
typename decay::type>(forward(a), forward(b));
}

The complete implementation is even more complex: To support
std::ref() and std::cref(), the function also unwraps instances of
std::reference_wrapper into real references.
The C++ standard library now perfectly forwards passed arguments in many
places in similar way, often combined with using std::decay<>.

7.7 Summary
• When testing templates, use string literals of different length.
• Template parameters passed by value decay, while passing them by reference
does not decay.
• The type trait std::decay<> allows you to decay parameters in templates
passed by reference.
• In some cases std::cref() and std::ref() allow you to pass

arguments by reference when function templates declare them to be passed by
value.
• Passing template parameters by value is simple but may not result in the best
performance.
• Pass parameters to function templates by value unless there are good reasons to
do otherwise.
• Ensure that return values are usually passed by value (which might mean that a
template parameter can’t be specified directly as a return type).
• Always measure performance when it is important. Do not rely on intuition; it’s
probably wrong.
1 A constant rvalue reference X const&& is also possible but there is no
established semantic meaning for it.
2 Note that since C++17 you can pass temporary entities (rvalues) by value
even if no copy or move constructor is available (see Section B.2.1 on page
676). So, since C++17 the additional constraint is that copying for lvalues is
not possible.
3 The implementation of the string class might itself have some optimizations to
make copying cheaper. One is the small string optimization (SSO), using some
memory directly inside the object to hold the value without allocating memory
as long as the value is not too long. Another is the copy-on-write optimization,
which creates a copy using the same memory as the source as long as neither
source nor the copy is modified. However, the copy-on-write optimization has
significant drawbacks in multithreaded code. For this reason, it is forbidden
for standard strings since C++11.
4 The term decay comes from C, and also applies to the type conversion from a
function to a function pointer (see Section 11.1.1 on page 159).
5 The use of const_cast is another, more explicit, way to modify the
referenced object.
6 When passing std::move(c), std::move() first converts c to
std::string const&&, which then has the effect that T is deduced as
std::string const.
7 You can also call get() on a reference wrapper and use it as function object.
8 See C++ library issue 181 [LibIssue181] for details.

Chapter 8
Compile-Time Programming
C++ has always included some simple ways to compute values at compile time.
Templates considerably increased the possibilities in this area, and further
evolution of the language has only added to this toolbox.
In the simple case, you can decide whether or not to use certain or to choose
between different template code. But the compiler even can compute the
outcome of control flow at compile time, provided all necessary input is
available.
In fact, C++ has multiple features to support compile-time programming: •
Since before C++98, templates have provided the ability to compute at compile
time, including using loops and execution path selection. (However, some
consider this an “abuse” of template features, e.g., because it requires
nonintuitive syntax.) • With partial specialization we can choose at compile time
between different class template implementations depending on specific
constraints or requirements.
• With the SFINAE principle, we can allow selection between different function
template implementations for different types or different constraints.
• In C++11 and C++14, compile-time computing became increasingly better
supported with the constexpr feature using “intuitive” execution path
selection and, since C++14, most statement kinds (including for loops,
switch statements, etc.).
• C++17 introduced a “compile-time if” to discard statements depending on
compile-time conditions or constraints. It works even outside of templates.
This chapter introduces these features with a special focus on the role and
context of templates.

8.1 Template Metaprogramming
Templates are instantiated at compile time (in contrast to dynamic languages,
where genericity is handled at run time). It turns out that some of the features of

C++ templates can be combined with the instantiation process to produce a sort
of primitive recursive “programming language” within the C++ language itself.1
For this reason, templates can be used to “compute a program.” Chapter 23 will
cover the whole story and all features, but here is a short example of what is
possible.
The following code finds out at compile time whether a given number is a
prime number: Click here to view code image
basics/isprime.hpp
template // p: number to check, d: current
divisor
struct DoIsPrime {
static constexpr bool value = (p%d != 0) && DoIsPrime::value;
};
template // end recursion if divisor is 2
struct DoIsPrime {
static constexpr bool value = (p%2 != 0);
};
template // primary template
struct IsPrime {
// start recursion with divisor from p/2:
static constexpr bool value = DoIsPrime::value;
};
// special cases (to avoid endless recursion with template
instantiation):
template<>
struct IsPrime<0> { static constexpr bool value = false; };
template<>
struct IsPrime<1> { static constexpr bool value = false; };
template<>
struct IsPrime<2> { static constexpr bool value = true; };
template<>
struct IsPrime<3> { static constexpr bool value = true; }; The
IsPrime<> template returns in member value whether the passed template
parameter p is a prime number. To achieve this, it instantiates
DoIsPrime<>, which recursively expands to an expression checking for
each divisor d between p/2 and 2 whether the divisor divides p without
remainder.

For example, the expression
IsPrime<9>::value

expands to
DoIsPrime<9,4>::value

which expands to Click here to view code image
9%4!=0 && DoIsPrime<9,3>::value which expands to
Click here to view code image
9%4!=0 && 9%3!=0 && DoIsPrime<9,2>::value which expands to
Click here to view code image
9%4!=0 && 9%3!=0 && 9%2!=0

which evaluates to false, because 9%3 is 0.
As this chain of instantiations demonstrates: • We use recursive expansions of
DoIsPrime<> to iterate over all divisors from p/2 down to 2 to find out
whether any of these divisors divide the given integer exactly (i.e., without
remainder).
• The partial specialization of DoIsPrime<> for d equal to 2 serves as the
criterion to end the recursion.
Note that all this is done at compile time. That is, IsPrime<9>::value
expands to false at compile time.
The template syntax is arguably clumsy, but code similar to this has been valid
since C++98 (and earlier) and has proven useful for quite a few libraries.2
See Chapter 23 for details.

8.2 Computing with constexpr
C++11 introduced a new feature, constexpr, that greatly simplifies various
forms of compile-time computation. In particular, given proper input, a
constexpr function can be evaluated at compile time. While in C++11
constexpr functions were introduced with stringent limitations (e.g., each
constexpr function definition was essentially limited to consist of a return
statement), most of these restrictions were removed with C++14. Of course,
successfully evaluating a constexpr function still requires that all
computational steps be possible and valid at compile time: Currently, that
excludes things like heap allocation or throwing exceptions.
Our example to test whether a number is a prime number could be
implemented as follows in C++11: Click here to view code image
basics/isprime11.hpp
constexpr bool

doIsPrime (unsigned p, unsigned d) // p: number to check, d: current
divisor
{
return d!=2 ? (p%d!=0) && doIsPrime(p,d-1) // check this and smaller
divisors
: (p%2!=0); // end recursion if divisor is 2
}
constexpr bool isPrime (unsigned p)
{
return p < 4 ? !(p<2) // handle special cases
: doIsPrime(p,p/2); // start recursion with divisor from p/2
}

Due to the limitation of having only one statement, we can only use the
conditional operator as a selection mechanism, and we still need recursion to
iterate over the elements. But the syntax is ordinary C++ function code, making
it more accessible than our first version relying on template instantiation.
With C++14, constexpr functions can make use of most control structures
available in general C++ code. So, instead of writing unwieldy template code or
somewhat arcane one-liners, we can now just use a plain for loop: Click here to
view code image
basics/isprime14.hpp
constexpr bool isPrime (unsigned int p)
{
for (unsigned int d=2; d<=p/2; ++d) {
if (p % d == 0) {
return false; // found divisor without remainder
}
}
return p > 1; // no divisor without remainder found
}

With both the C++11 and C++14 versions of our constexpr isPrime()
implementations, we can simply call isPrime(9)
to find out whether 9 is a prime number. Note that it can do so at compile time,
but it need not necessarily do so. In a context that requires a compile-time value
(e.g., an array length or a nontype template argument), the compiler will attempt
to evaluate a call to a constexpr function at compile time and issue an error if
that is not possible (since a constant must be produced in the end). In other
contexts, the compiler may or may not attempt the evaluation at compile time3
but if such an evaluation fails, no error is issued and the call is left as a run-time

call instead.
For example:
Click here to view code image
constexpr bool b1 = isPrime(9); // evaluated at compile time

will compute the value at compile time. The same is true with Click here to view
code image
const bool b2 = isPrime(9); // evaluated at compile time if in
namespace scope

provided b2 is defined globally or in a namespace. At block scope, the compiler
can decide whether to compute it at compile or run time.4 This, for example, is
also the case here: Click here to view code image
bool fiftySevenIsPrime() {
return isPrime(57); // evaluated at compile or running time
}

the compiler may or may not evaluate the call to isPrime at compile time.
On the other hand:
Click here to view code image
int x;
…
std::cout << isPrime(x); // evaluated at run time

will generate code that computes at run time whether x is a prime number.

8.3 Execution Path Selection with Partial
Specialization
An interesting application of a compile-time test such as isPrime() is to use
partial specialization to select at compile time between different
implementations.
For example, we can choose between different implementations depending on
whether a template argument is a prime number: Click here to view code image
// primary helper template:
template
struct Helper;
// implementation if SZ is not a prime number:
template

struct Helper
{
…
};
// implementation if SZ is a prime number:
template
struct Helper
{
…
};
template
long foo (std::array const& coll)
{
Helper h; // implementation depends on whether array has prime
number as size
…
}

Here, depending on whether the size of the std::array<> argument is a
prime number, we use two different implementations of class Helper<>. This
kind of application of partial specialization is broadly applicable to select among
different implementations of a function template depending on properties of the
arguments it’s being invoked for.
Above, we used two partial specializations to implement the two possible
alternatives. Instead, we can also use the primary template for one of the
alternatives (the default) case and partial specializations for any other special
case: Click here to view code image
// primary helper template (used if no specialization fits):
template
struct Helper
{
…
};
// special implementation if SZ is a prime number:
template
struct Helper
{
…
};

Because function templates do not support partial specialization, you have to use

other mechanisms to change function implementation based on certain
constraints. Our options include the following: • Use classes with static
functions, • Use std::enable_if, introduced in Section 6.3 on page 98, •
Use the SFINAE feature, which is introduced next, or • Use the compile-time if
feature, available since C++17, which is introduced below in Section 8.5 on page
135.
Chapter 20 discusses techniques for selecting a function implementation based
on constraints.

8.4 SFINAE (Substitution Failure Is Not An Error)
In C++ it is pretty common to overload functions to account for various
argument types. When a compiler sees a call to an overloaded function, it must
therefore consider each candidate separately, evaluating the arguments of the call
and picking the candidate that matches best (see also Appendix C for some
details about this process).
In cases where the set of candidates for a call includes function templates, the
compiler first has to determine what template arguments should be used for that
candidate, then substitute those arguments in the function parameter list and in
its return type, and then evaluate how well it matches (just like an ordinary
function). However, the substitution process could run into problems: It could
produce constructs that make no sense. Rather than deciding that such
meaningless substitutions lead to errors, the language rules instead say that
candidates with such substitution problems are simply ignored.
We call this principle SFINAE (pronounced like sfee-nay), which stands for
“substitution failure is not an error.”
Note that the substitution process described here is distinct from the ondemand instantiation process (see Section 2.2 on page 27): The substitution may
be done even for potential instantiations that are not needed (so the compiler can
evaluate whether indeed they are unneeded). It is a substitution of the constructs
appearing directly in the declaration of the function (but not its body).
Consider the following example: Click here to view code image
basics/len1.hpp
// number of elements in a raw array:
template
std::size_t len (T(&)[N])
{

return N;
}
// number of elements for a type having size_type:
template
typename T::size_type len (T const& t)
{
return t.size();
}

Here, we define two function templates len() taking one generic argument:5
1. The first function template declares the parameter as T(&)[N], which means
that the parameter has to be an array of N elements of type T.
2. The second function template declares the parameter simply as T, which
places no constraints on the parameter but returns type T::size_type,
which requires that the passed argument type has a corresponding member
size_type.
When passing a raw array or string literals, only the function template for raw
arrays matches: Click here to view code image
int a[10];
std::cout << len(a); // OK: only len() for array matches
std::cout << len("tmp"); //OK: only len() for array matches

According to its signature, the second function template also matches when
substituting (respectively) int[10] and char const[4] for T, but those
substitutions lead to potential errors in the return type T::size_type. The
second template is therefore ignored for these calls.
When passing a std::vector<>, only the second function template
matches: Click here to view code image
std::vector v;
std::cout << len(v); // OK: only len() for a type with size_type
matches

When passing a raw pointer, neither of the templates match (without a failure).
As a result, the compiler will complain that no matching len() function is
found: Click here to view code image
int* p;
std::cout << len(p); // ERROR: no matching len() function found

Note that this differs from passing an object of a type having a size_type
member, but no size() member function, as is, for example, the case for
std::allocator<>: Click here to view code image

std::allocator x;
std::cout << len(x); // ERROR: len() function found, but can’t size()

When passing an object of such a type, the compiler finds the second function
template as matching function template. So instead of an error that no matching
len() function is found, this will result in a compile-time error that calling
size() for a std::allocator is invalid. This time, the second
function template is not ignored.
Ignoring a candidate when substituting its return type is meaningless can
cause the compiler to select another candidate whose parameters are a worse
match. For example: Click here to view code image
basics/len2.hpp
// number of elements in a raw array:
template
std::size_t len (T(&)[N])
{
return N;
}
// number of elements for a type having size_type:
template
typename T::size_type len (T const& t)
{
return t.size();
}
// fallback for all other types:
std::size_t len (…)
{
return 0;
}

Here, we also provide a general len() function that always matches but has the
worst match (match with ellipsis (…) in overload resolution (see Section C.2 on
page 682).
So, for raw arrays and vectors, we have two matches where the specific match
is the better match. For pointers, only the fallback matches so that the compiler
no longer complains about a missing len() for this call.6 But for the allocator,
the second and third function templates match, with the second function template
as the better match. So, still, this results in an error that no size() member
function can be called: Click here to view code image
int a[10];
std::cout << len(a); // OK: len() for array is best match

std::cout << len("tmp"); //OK: len() for array is best match
std::vector v;
std::cout << len(v); // OK: len() for a type with size_type is best
match
int* p;
std::cout << len(p); // OK: only fallback len() matches
std::allocator x;
std::cout << len(x); // ERROR: 2nd len() function matches best,
// but can’t call size() for x

See Section 15.7 on page 284 for more details about SFINAE and Section 19.4
on page 416 about some applications of SFINAE.
SFINAE and Overload Resolution
Over time, the SFINAE principle has become so important and so prevalent
among template designers that the abbreviation has become a verb. We say “we
SFINAE out a function” if we mean to apply the SFINAE mechanism to ensure
that function templates are ignored for certain constraints by instrumenting the
template code to result in invalid code for these constraints. And whenever you
read in the C++ standard that a function template “shall not participate in
overload resolution unless…” it means that SFINAE is used to “SFINAE out”
that function template for certain cases.
For example, class std::thread declares a constructor: Click here to view
code image
namespace std {
class thread {
public:
…
template
explicit thread(F&& f, Args&&… args);
…
};
}

with the following remark:
Remarks: This constructor shall not participate in overload resolution if
decay_t is the same type as std::thread.
This means that the template constructor is ignored if it is called with a
std::thread as first and only argument. The reason is that otherwise a

member template like this sometimes might better match than any predefined
copy or move constructor (see Section 6.2 on page 95 and Section 16.2.4 on
page 333 for details). By SFINAE’ing out the constructor template when called
for a thread, we ensure that the predefined copy or move constructor is always
used when a thread gets constructed from another thread.7
Applying this technique on a case-by-case basis can be unwieldy. Fortunately,
the standard library provides tools to disable templates more easily. The bestknown such feature is std::enable_if<>, which was introduced in Section
6.3 on page 98. It allows us to disable a template just by replacing a type with a
construct containing the condition to disable it.
As a consequence, the real declaration of std::thread typically is as
follows: Click here to view code image
namespace std {
class thread {
public:
…
template,
thread>>>
explicit thread(F&& f, Args&&… args);
…
};
}

See Section 20.3 on page 469 for details about how std::enable_if<> is
implemented, using partial specialization and SFINAE.

8.4.1 Expression SFINAE with decltype
It’s not always easy to find out and formulate the right expression to SFINAE out
function templates for certain conditions.
Suppose, for example, that we want to ensure that the function template
len() is ignored for arguments of a type that has a size_type member but
not a size() member function. Without any form of requirements for a
size() member function in the function declaration, the function template is
selected and its ultimate instantiation then results in an error: Click here to view
code image
template
typename T::size_type len (T const& t)
{

return t.size();
}
std::allocator x;
std::cout << len(x) << ’\n’; //ERROR: len() selected, but x has no
size()

There is a common pattern or idiom to deal with such a situation: • Specify the
return type with the trailing return type syntax (use auto at the front and ->
before the return type at the end).
• Define the return type using decltype and the comma operator.
• Formulate all expressions that must be valid at the beginning of the comma
operator (converted to void in case the comma operator is overloaded).
• Define an object of the real return type at the end of the comma operator.
For example:
Click here to view code image
template
auto len (T const& t) -> decltype( (void)(t.size()), T::size_type() )
{
return t.size();
}

Here the return type is given by Click here to view code image
decltype( (void)(t.size)(), T::size_type() ) The operand of the
decltype construct is a comma-separated list of expressions, so that
the last expression T::size_type() yields a value of the desired
return type (which decltype uses to convert into the return type).
Before the (last) comma, we have the expressions that must be valid,
which in this case is just t.size(). The cast of the expression to
void is to avoid the possibility of a user-defined comma operator
overloaded for the type of the expressions.

Note that the argument of decltype is an unevaluated operand, which
means that you, for example, can create “dummy objects” without calling
constructors, which is discussed in Section 11.2.3 on page 166.

8.5 Compile-Time if
Partial specialization, SFINAE, and std::enable_if allow us to enable or
disable templates as a whole. C++17 additionally introduces a compile-time if
statement that allows is to enable or disable specific statements based on
compile-time conditions. With the syntax if constexpr(… ), the compiler

uses a compile-time expression to decide whether to apply the then part or the
else part (if any).
As a first example, consider the variadic function template print()
introduced in Section 4.1.1 on page 55. It prints its arguments (of arbitrary types)
using recursion. Instead of providing a separate function to end the recursion, the
constexpr if feature allows us to decide locally whether to continue the
recursion:8
Click here to view code image
template
void print (T const& firstArg, Types const&… args)
{
std::cout << firstArg << ’\n’;
if constexpr(sizeof…(args) > 0) {
print(args…); //code only available if sizeof…(args)>0 (since C++17)
}
}

Here, if print() is called for one argument only, args becomes an empty
parameter pack so that sizeof…(args) becomes 0. As a result, the recursive
call of print() becomes a discarded statement, for which the code is not
instantiated. Thus, a corresponding function is not required to exist and the
recursion ends.
The fact that the code is not instantiated means that only the first translation
phase (the definition time) is performed, which checks for correct syntax and
names that don’t depend on template parameters (see Section 1.1.3 on page 6).
For example: Click here to view code image
template
void foo(T t)
{
if constexpr(std::is_integral_v) {
if (t > 0) {
foo(t-1); // OK
}
}
else {
undeclared(t); // error if not declared and not discarded (i.e. T is
not integral)
undeclared(); // error if not declared (even if discarded)
static_assert(false, "no integral"); // always asserts (even if
discarded)
static_assert(!std::is_integral_v, "no integral"); //OK
}
}

Note that if constexpr can be used in any function, not only in templates.

We only need a compile-time expression that yields a Boolean value. For
example: Click here to view code image
int main()
{
if constexpr(std::numeric_limits::is_signed {
foo(42); // OK
}
else {
undeclared(42); // error if
undeclared() not declared
static_assert(false, "unsigned"); // always asserts (even if
discarded)
static_assert(!std::numeric_limits::is_signed,
"char is unsigned"); //OK
}
}

With this feature, we can, for example, use our isPrime() compile-time
function, introduced in Section 8.2 on page 125, to perform additional code if a
given size is not a prime number: Click here to view code image
template
void foo (std::array const& coll)
{
if constexpr(!isPrime(SZ)) {
… //special additional handling if the passed array has no prime
number as size
}
…
}

See Section 14.6 on page 263 for further details.

8.6 Summary
• Templates provide the ability to compute at compile time (using recursion to
iterate and partial specialization or operator ?: for selections).
• With constexpr functions, we can replace most compile-time computations
with “ordinary functions” that are callable in compile-time contexts.
• With partial specialization, we can choose between different implementations
of class templates based on certain compile-time constraints.
• Templates are used only if needed and substitutions in function template
declarations do not result in invalid code. This principle is called SFINAE
(substitution failure is not an error).

• SFINAE can be used to provide function templates only for certain types
and/or constraints.
• Since C++17, a compile-time if allows us to enable or discard statements
according to compile-time conditions (even outside templates).
1

In fact, it was Erwin Unruh who first found it out by presenting a program
computing prime numbers at compile time. See Section 23.7 on page 545 for
details.
2 Before C++11, it was common to declare the value members as enumerator
constants instead of static data members to avoid the need to have an out-ofclass definition of the static data member (see Section 23.6 on page 543 for
details). For example: Click here to view code image
enum { value = (p%d != 0) && DoIsPrime::value }; 3 At the time
of writing this book in 2012"fn">4 Theoretically, even with
constexpr, the compiler can decide to compute the initial value of b
at run time.
5

We don’t name this function size() because we want to avoid a naming
conflict with the C++ standard library, which defines a standard function
template std::size() since C++17.
6 In practice, such a fallback function would usually provide a more useful
default, throw an exception, or contain a static assertion to result in a useful
error message.
7 Since the copy constructor for class thread is deleted, this also ensures that
copying is forbidden.
8 Although the code reads if constexpr, the feature is called constexpr if,
because it is the “constexpr” form of if (and for historical reasons).

Chapter 9
Using Templates in Practice
Template code is a little different from ordinary code. In some ways templates lie
somewhere between macros and ordinary (nontemplate) declarations. Although
this may be an oversimplification, it has consequences not only for the way we
write algorithms and data structures using templates but also for the day-to-day
logistics of expressing and analyzing programs involving templates.
In this chapter we address some of these practicalities without necessarily
delving into the technical details that underlie them. Many of these details are
explored in Chapter 14. To keep the discussion simple, we assume that our C++
compilation systems consist of fairly traditional compilers and linkers (C++
systems that don’t fall in this category are rare).

9.1 The Inclusion Model
There are several ways to organize template source code. This section presents
the most popular approach: the inclusion model.

9.1.1 Linker Errors
Most C and C++ programmers organize their nontemplate code largely as
follows: • Classes and other types are entirely placed in header files. Typically,
this is a file with a .hpp (or .H, .h, .hh, .hxx) filename extension.
• For global (noninline) variables and (noninline) functions, only a declaration is
put in a header file, and the definition goes into a file compiled as its own
translation unit. Such a CPP file typically is a file with a .cpp (or .C, .c,
.cc, or .cxx) filename extension.
This works well: It makes the needed type definition easily available throughout
the program and avoids duplicate definition errors on variables and functions
from the linker.

With these conventions in mind, a common error about which beginning
template programmers complain is illustrated by the following (erroneous) little
program. As usual for “ordinary code,” we declare the template in a header file:
Click here to view code image
basics/myfirst.hpp
#ifndef MYFIRST_HPP
#define MYFIRST_HPP
// declaration of template
template
void printTypeof (T const&);
#endif //MYFIRST_HPP

printTypeof() is the declaration of a simple auxiliary function that prints
some type information. The implementation of the function is placed in a CPP
file: Click here to view code image
basics/myfirst.cpp
#include 
#include 
#include "myfirst.hpp"
// implementation/definition of template
template
void printTypeof (T const& x)
{
std::cout << typeid(x).name() << ’\n’;
}

The example uses the typeid operator to print a string that describes the type
of the expression passed to it. It returns an lvalue of the static type
std::type_info, which provides a member function name() that shows
the types of some expressions. The C++ standard doesn’t actually say that
name() must return something meaningful, but on good C++ implementations,
you should get a string that gives a good description of the type of the expression
passed to typeid.1
Finally, we use the template in another CPP file, into which our template
declaration is #included: Click here to view code image
basics/myfirstmain.cpp

#include "myfirst.hpp"
// use of the template
int main()
{
double ice = 3.0;
printTypeof(ice); // call function template for type double
}

A C++ compiler will most likely accept this program without any problems, but
the linker will probably report an error, implying that there is no definition of the
function printTypeof().
The reason for this error is that the definition of the function template
printTypeof() has not been instantiated. In order for a template to be
instantiated, the compiler must know which definition should be instantiated and
for what template arguments it should be instantiated. Unfortunately, in the
previous example, these two pieces of information are in files that are compiled
separately. Therefore, when our compiler sees the call to printTypeof() but
has no definition in sight to instantiate this function for double, it just assumes
that such a definition is provided elsewhere and creates a reference (for the
linker to resolve) to that definition. On the other hand, when the compiler
processes the file myfirst.cpp, it has no indication at that point that it must
instantiate the template definition it contains for specific arguments.

9.1.2 Templates in Header Files
The common solution to the previous problem is to use the same approach that
we would take with macros or with inline functions: We include the definitions
of a template in the header file that declares that template.
That is, instead of providing a file myfirst.cpp, we rewrite
myfirst.hpp so that it contains all template declarations and template
definitions: Click here to view code image
basics/myfirst2.hpp
#ifndef MYFIRST_HPP
#define MYFIRST_HPP
#include 
#include 

// declaration of template
template
void printTypeof (T const&);
// implementation/definition of template
template
void printTypeof (T const& x)
{
std::cout << typeid(x).name() << ’\n’; }
#endif //MYFIRST_HPP

This way of organizing templates is called the inclusion model. With this in
place, you should find that our program now correctly compiles, links, and
executes.
There are a few observations we can make at this point. The most notable is
that this approach has considerably increased the cost of including the header file
myfirst.hpp. In this example, the cost is not the result of the size of the
template definition itself but the result of the fact that we must also include the
headers used by the definition of our template—in this case  and
. You may find that this amounts to tens of thousands of lines of
code because headers like  contain many template definitions of
their own.
This is a real problem in practice because it considerably increases the time
needed by the compiler to compile significant programs. We will therefore
examine some possible ways to approach this problem, including precompiled
headers (see Section 9.3 on page 141) and the use of explicit template
instantiation (see Section 14.5 on page 260).
Despite this build-time issue, we do recommend following this inclusion
model to organize your templates when possible until a better mechanism
becomes available. At the time of writing this book in 2017, such a mechanism
is in the works: modules, which is introduced in Section 17.11 on page 366.
They are a language mechanism that allows the programmer to more logically
organize code in such a way that a compiler can separately compile all
declarations and then efficiently and selectively import the processed
declarations whenever needed.
Another (more subtle) observation about the inclusion approach is that
noninline function templates are distinct from inline functions and macros in an
important way: They are not expanded at the call site. Instead, when they are
instantiated, they create a new copy of a function. Because this is an automatic
process, a compiler could end up creating two copies in two different files, and

some linkers could issue errors when they find two distinct definitions for the
same function. In theory, this should not be a concern of ours: It is a problem for
the C++ compilation system to accommodate. In practice, things work well most
of the time, and we don’t need to deal with this issue at all. For large projects
that create their own library of code, however, problems occasionally show up. A
discussion of instantiation schemes in Chapter 14 and a close study of the
documentation that came with the C++ translation system (compiler) should help
address these problems.
Finally, we need to point out that what applies to the ordinary function
template in our example also applies to member functions and static data
members of class templates, as well as to member function templates.

9.2 Templates and inline
Declaring functions to be inline is a common tool to improve the running time of
programs. The inline specifier was meant to be a hint for the implementation
that inline substitution of the function body at the point of call is preferred over
the usual function call mechanism.
However, an implementation may ignore the hint. Hence, the only guaranteed
effect of inline is to allow a function definition to appear multiple times in a
program (usually because it appears in a header file that is included in multiple
places).
Like inline functions, function templates can be defined in multiple translation
units. This is usually achieved by placing the definition in a header file that is
included by multiple CPP files.
This doesn’t mean, however, that function templates use inline substitutions
by default. It is entirely up to the compiler whether and when inline substitution
of a function template body at the point of call is preferred over the usual
function call mechanism. Perhaps surprisingly, compilers are often better than
programmers at estimating whether inlining a call would lead to a net
performance improvement. As a result, the precise policy of a compiler with
respect to inline varies from compiler to compiler, and even depends on the
options selected for a specific compilation.
Nevertheless, with appropriate performance monitoring tools, a programmer
may have better information than a compiler and may therefore wish to override
compiler decisions (e.g., when tuning software for particular platforms, such as
mobiles phones, or particular inputs). Sometimes this is only possible with

compiler-specific attributes such as noinline or always_inline.
It’s worth pointing out at this point that full specializations of function
templates act like ordinary functions in this regard: Their definition can appear
only once unless they’re defined inline (see Section 16.3 on page 338). See
also Appendix A for a broader, detailed overview of this topic.

9.3 Precompiled Headers
Even without templates, C++ header files can become very large and therefore
take a long time to compile. Templates add to this tendency, and the outcry of
waiting programmers has in many cases driven vendors to implement a scheme
usually known as precompiled headers (PCH). This scheme operates outside the
scope of the standard and relies on vendor-specific options. Although we leave
the details on how to create and use precompiled header files to the
documentation of the various C++ compilation systems that have this feature, it
is useful to gain some understanding of how it works.
When a compiler translates a file, it does so starting from the beginning of the
file and working through to the end. As it processes each token from the file
(which may come from #included files), it adapts its internal state, including
such things as adding entries to a table of symbols so they may be looked up
later. While doing so, the compiler may also generate code in object files.
The precompiled header scheme relies on the fact that code can be organized
in such a manner that many files start with the same lines of code. Let’s assume
for the sake of argument that every file to be compiled starts with the same N
lines of code. We could compile these N lines and save the complete state of the
compiler at that point in a precompiled header. Then, for every file in our
program, we could reload the saved state and start compilation at line N+1. At
this point it is worthwhile to note that reloading the saved state is an operation
that can be orders of magnitude faster than actually compiling the first N lines.
However, saving the state in the first place is typically more expensive than just
compiling the N lines. The increase in cost varies roughly from 20 to 200
percent.
#include  The key to making effective use of precompiled
headers is to ensure that—as much as possible— files start with a
maximum number of common lines of code. In practice this means the
files must start with the same #include directives, which (as
mentioned earlier) consume a substantial portion of our build time.
Hence, it can be very advantageous to pay attention to the order in

which headers are included. For example, the following two files:
#include 
#include 
…

and
#include 
#include 
…

inhibit the use of precompiled headers because there is no common initial state
in the sources.
Some programmers decide that it is better to #include some extra
unnecessary headers than to pass on an opportunity to accelerate the translation
of a file using a precompiled header. This decision can considerably ease the
management of the inclusion policy. For example, it is usually relatively
straightforward to create a header file named std.hpp that includes all the
standard headers:2
#include 
#include 
#include 
#include 
#include 
…

This file can then be precompiled, and every program file that makes use of the
standard library can then simply be started as follows: #include "std.hpp"
…
Normally this would take a while to compile, but given a system with sufficient
memory, the pre-compiled header scheme allows it to be processed significantly
faster than almost any single standard header would require without
precompilation. The standard headers are particularly convenient in this way
because they rarely change, and hence the precompiled header for our std.hpp
file can be built once. Otherwise, precompiled headers are typically part of the
dependency configuration of a project (e.g., they are updated as needed by the
popular make tool or an integrated development environment’s (IDE) project
build tool).
One attractive approach to manage precompiled headers is to create layers of
precompiled headers that go from the most widely used and stable headers (e.g.,
our std.hpp header) to headers that aren’t expected to change all the time and
therefore are still worth precompiling. However, if headers are under heavy
development, creating precompiled headers for them can take more time than

what is saved by reusing them. A key concept to this approach is that a
precompiled header for a more stable layer can be reused to improve the
precompilation time of a less stable header. For example, suppose that in
addition to our std.hpp header (which we have precompiled), we also define a
core.hpp header that includes additional facilities that are specific to our
project but nonetheless achieve a certain level of stability: #include "std.hpp"
#include "core_data.hpp
#include "core_algos.hpp"
…
Because this file starts with #include "std.hpp", the compiler can load
the associated precom-piled header and continue with the next line without
recompiling all the standard headers. When the file is completely processed, a
new precompiled header can be produced. Applications can then use #include
"core.hpp" to provide access quickly to large amounts of functionality
because the compiler can load the latter precompiled header.

9.4 Decoding the Error Novel
Ordinary compilation errors are normally quite succinct and to the point. For
example, when a compiler says “class X has no member ’fun’,” it
usually isn’t too hard to figure out what is wrong in our code (e.g., we might
have mistyped run as fun). Not so with templates. Let’s look at some
examples.
Simple Type Mismatch
Consider the following relatively simple example using the C++ standard
library: Click here to view code image
basics/errornovel1.cpp
#include 
#include 
#include 
int main()
{
std::map coll;
…
// find the first nonempty string in coll:
auto pos = std::find_if (coll.begin(), coll.end(),

[] (std::string const& s){
return s != "";
});
}

It contains a fairly small mistake: In the lambda used to find the first matching
string in the collection, we check against a given string. However, the elements
in a map are key/value pairs, so that we should expect a
std::pair.
A version of the popular GNU C++ compiler reports the following error: Click
here to view code image
1 In file included from /cygdrive/p/gcc/gcc61include/bits/stl_algobase.h:71:0,
2 from /cygdrive/p/gcc/gcc61-include/bits/char_traits.h:39,
3 from /cygdrive/p/gcc/gcc61-include/string:40,
4 from errornovel1.cpp:1:
5 /cygdrive/p/gcc/gcc61-include/bits/predefined_ops.h: In
instantiation of 'bool __gnu_cxx
::__ops::_Iter_pred<_Predicate>::operator()(_Iterator) [with
_Iterator = std::_Rb_tree_i
terator, double>
>; _Predicate = main()
::]':
6 /cygdrive/p/gcc/gcc61-include/bits/stl_algo.h:104:42: required
from '_InputIterator
std::__find_if(_InputIterator, _InputIterator, _Predicate,
std::input_iterator_tag)
[with _InputIterator = std::_Rb_tree_iterator, double> >; _Predicate =
__gnu_cxx::__ops::_Iter_pred >]'
7 /cygdrive/p/gcc/gcc61-include/bits/stl_algo.h:161:23: required
from '_Iterator std::__
find_if(_Iterator, _Iterator, _Predicate) [with _Iterator =
std::_Rb_tree_iterator, double> >; _Predicate
= __gnu_cxx::__ops::_
Iter_pred >]'
8 /cygdrive/p/gcc/gcc61-include/bits/stl_algo.h:3824:28: required
from '_IIter std::find
_if(_IIter, _IIter, _Predicate) [with _IIter =
std::_Rb_tree_iterator, double> >; _Predicate = main()::
]'
9 errornovel1.cpp:13:29: required from here
10 /cygdrive/p/gcc/gcc61-include/bits/predefined_ops.h:234:11:
error: no match for call to

'(main()::) (std::pair,
double>&)'
11 { return bool(_M_pred(*__it)); }
12 ^~~~~~~~~~~~~~~~~~~~
13 /cygdrive/p/gcc/gcc61-include/bits/predefined_ops.h:234:11:
note: candidate: bool (*)(
const string&) {aka bool (*)(const
std::__cxx11::basic_string&)} 
14 /cygdrive/p/gcc/gcc61-include/bits/predefined_ops.h:234:11:
note: candidate expects 2
arguments, 2 provided
15 errornovel1.cpp:11:52: note: candidate: main()::
16 [] (std::string const& s) {
17 ^
18 errornovel1.cpp:11:52: note: no known conversion for argument 1
from 'std::pair, double>' to 'const string& {aka
const std::__cxx11::
basic_string&}'

A message like this starts looking more like a novel than a diagnostic. It can also
be overwhelming to the point of discouraging novice template users. However,
with some practice, messages like this become manageable, and the errors are at
least relatively easily located.
The first part of this error message says that an error occurred in a function
template instance deep inside an internal predefined_ops.h header,
included from errornovel1.cpp via various other headers. Here and in the
following lines, the compiler reports what was instantiated with which
arguments. In this case, it all started with the statement ending on line 13 of
errornovel1.cpp, which is: Click here to view code image
auto pos = std::find_if (coll.begin(), coll.end(), [] (std::string
const& s) {
return s != "";
});

This caused the instantiation of a find_if template on line 115 of the
stl_algo.h header, where the code Click here to view code image
_IIter std::find_if(_IIter, _IIter, _Predicate)

is instantiated with
Click here to view code image
_IIter = std::_Rb_tree_iterator,
double> >

_Predicate = main()::

The compiler reports all this in case we simply were not expecting all these
templates to be instantiated. It allows us to determine the chain of events that
caused the instantiations.
However, in our example, we’re willing to believe that all kinds of templates
needed to be instantiated, and we just wonder why it didn’t work. This
information comes in the last part of the message: The part that says “no
match for call” implies that a function call could not be resolved because
the types of the arguments and the parameter types didn’t match. It lists what is
called Click here to view code image
(main()::) (std::pair,
double>&)

and code that caused this call:
Click here to view code image
{ return bool(_M_pred(*__it)); }

Furthermore, just after this, the line containing “note: candidate:”
explains that there was a single candidate type expecting a const string&
and that this candidate is defined in line 11 of errornovel1.cpp as lambda
[] (std::string const& s) combined with a reason why a possible
candidate didn’t fit: Click here to view code image
no known conversion for argument 1
from ’std::pair, double>’
to ’const string& {aka const std::__cxx11::basic_string&}’

which describes the problem we have.
There is no doubt that the error message could be better. The actual problem
could be emitted before the history of the instantiation, and instead of using fully
expanded template instantiation names like
std::__cxx11::basic_string, using just std::string
might be enough. However, it is also true that all the information in this
diagnostic could be useful in some situations. It is therefore not surprising that
other compilers provide similar information (although some use the structuring
techniques mentioned).
For example, the Visual C++ compiler outputs something like: Click here to
view code image
1 c:\tools_root\cl\inc\algorithm(166): error C2664: 'bool main::
::operator ()(const std::string &) const': cannot
convert argument 1 from
'std::pair' to 'const std::string &'
2 with
3 [
4 _Kty=std::string,
5 _Ty=double
6 ]
7 c:\tools_root\cl\inc\algorithm(166): note: Reason: cannot
convert from 'std::pair' to 'const std::string'
8 with
9 [
10 _Kty=std::string,
11 _Ty=double
12 ]
13 c:\tools_root\cl\inc\algorithm(166): note: No user-definedconversion operator available
that can perform this conversion, or the operator cannot be called
14 c:\tools_root\cl\inc\algorithm(177): note: see reference to
function template instantiat
ion '_InIt
std::_Find_if_unchecked,_Pr>
(_InIt,_In
It,_Pr &)' being compiled
15 with
16 [
17
_InIt=std::_Tree_unchecked_iterator>>>,
18 _Mytree=std::_Tree_val>>,
19 _Pr=main::
20 ]
21 main.cpp(13): note: see reference to function template
instantiation '_InIt std::find_if
>>>
,main::>
(_InIt,_InIt,_Pr)' being compiled
22 with
23 [
24
_InIt=std::_Tree_iterator>>>,
25 _Kty=std::string,
26 _Ty=double,
27 _Pr=main::
28 ]

Here, again, we provide the chain of instantiations with the information telling

us what was instantiated by which arguments and where in the code, and we see
twice that we Click here to view code image
cannot convert from ’std::pair’ to ’const
std::string’
with
[
_Kty=std::string,
_Ty=double
]

Missing const on Some Compilers
Unfortunately, it sometimes happens that generic code is a problem only with
some compilers. Consider the following example: Click here to view code image
basics/errornovel2.cpp
#include 
#include 
class Customer
{
private:
std::string name;
public:
Customer (std::string const& n)
: name(n) {
}
std::string getName() const {
return name;
}
};
int main()
{
// provide our own hash function:
struct MyCustomerHash {
// NOTE: missing const is only an error with g++ and clang:
std::size_t operator() (Customer const& c) {
return std::hash()(c.getName());
}
};
// and use it for a hash table of Customers:
std::unordered_set coll; …
}

With Visual Studio 2013 or 2015, this code compiles as expected. However, with

g++ or clang, the code causes significant error messages. On g++ 6.1, for
example, the first error message is as follows: Click here to view code image
1 In file included from /cygdrive/p/gcc/gcc61include/bits/hashtable.h:35:0,
2 from /cygdrive/p/gcc/gcc61-include/unordered_set:47,
3 from errornovel2.cpp:2:
4 /cygdrive/p/gcc/gcc61-include/bits/hashtable_policy.h: In
instantiation of 'struct std::
__detail::__is_noexcept_hash':
5 /cygdrive/p/gcc/gcc61-include/type_traits:143:12: required from
'struct std::__and_<
std::__is_fast_hash,
std::__detail::__is_noexcept_hash >'
6 /cygdrive/p/gcc/gcc61-include/type_traits:154:38: required from
'struct std::__not_<
std::__and_,
std::__detail::__is_noexcept_
hash > >'
7 /cygdrive/p/gcc/gcc61-include/bits/unordered_set.h:95:63:
required from 'class std::
unordered_set'
8 errornovel2.cpp:28:47: required from here
9 /cygdrive/p/gcc/gcc61-include/bits/hashtable_policy.h:85:34:
error: no match for call to
'(const main()::MyCustomerHash) (const Customer&)'
10 noexcept(declval()(declval()))>
11 ~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~
12 errornovel2.cpp:22:17: note: candidate: std::size_t
main()::MyCustomerHash::operator()(
const Customer&) 
13 std::size_t operator() (const Customer& c) {
14 ^~~~~~~~
15 errornovel2.cpp:22:17: note: passing 'const
main()::MyCustomerHash*' as 'this' argument
discards qualifiers

immediately followed by more than 20 other error messages: 16 In file included
from /cygdrive/p/gcc/gcc61-include/bits/move.h:57:0,
18 from /cygdrive/p/gcc/gcc61-include/bits/stl_pair.h:59,
19 from /cygdrive/p/gcc/gcc61-include/bits/stl_algobase.h:64,
20 from /cygdrive/p/gcc/gcc61-include/bits/char_traits.h:39,
21 from /cygdrive/p/gcc/gcc61-include/string:40,
22 from errornovel2.cpp:1:
23 /cygdrive/p/gcc/gcc61-include/type_traits: In instantiation of 'struct
std::__not_,

std::__detail::__is_noexcept_hash<
Customer, main()::MyCustomerHash> > >':
24 /cygdrive/p/gcc/gcc61-include/bits/unordered_set.h:95:63: required from
'class std::
unordered_set'
25 errornovel2.cpp:28:47: required from here
26 /cygdrive/p/gcc/gcc61-include/type_traits:154:38: error: 'value' is not a
member of 'std
::__and_,
std::__detail::__is_noexcept_hash<
Customer, main()::MyCustomerHash> >'
27 : public integral_constant
28 ^~~~
29 In file included from /cygdrive/p/gcc/gcc61-include/unordered_set:48:0,
30 from errornovel2.cpp:2:
31 /cygdrive/p/gcc/gcc61-include/bits/unordered_set.h: In instantiation of 'class
std::
unordered_set':
32 errornovel2.cpp:28:47: required from here
33 /cygdrive/p/gcc/gcc61-include/bits/unordered_set.h:95:63: error: 'value' is not
a member
of 'std::__not_,
std::__detail::
__is_noexcept_hash > >'
34 typedef __uset_hashtable<_Value, _Hash, _Pred, _Alloc> _Hashtable;
35 ^~~~~~~~~~
36 /cygdrive/p/gcc/gcc61-include/bits/unordered_set.h:102:45: error: 'value' is
not a member
of 'std::__not_,
std::__detail::
__is_noexcept_hash > >'
37 typedef typename _Hashtable::key_type key_type;
38 ^~~~~~~~
…
Again, it’s hard to read the error message (even finding the beginning and end of
each message is a chore). The essence is that deep in header file
hashtable_policy.h in the instantiation of std::unordered_set<>
required by Click here to view code image

std::unordered_set coll; there is no match
for the call to
Click here to view code image
const main()::MyCustomerHash (const Customer&) in the instantiation
of
Click here to view code image
noexcept(declval()(declval()))>
~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~

(declval() is an expression of type
main()::MyCustomerHash). A possible “near match” candidate is Click
here to view code image
std::size_t main()::MyCustomerHash::operator()(const Customer&)

which is declared as
Click here to view code image
std::size_t operator() (const Customer& c) {
^~~~~~~~

and the last note says something about the problem: Click here to view code
image
passing ’const main()::MyCustomerHash*’ as ’this’ argument discards
qualifiers

Can you see what the problem is? This implementation of the
std::unordered_set class template requires that the function call operator
for the hash object be a const member function (see also Section 11.1.1 on
page 159). When that’s not the case, an error arises deep in the guts of the
algorithm.
All other error messages cascade from the first and go away when a const
qualifier is simply added to the hash function operator: Click here to view code
image
std::size_t operator() (const Customer& c) const {
…
}

Clang 3.9 gives the slightly better hint at the end of the first error message that
operator() of the hash functor is not marked const: Click here to view
code image
…
errornovel2.cpp:28:47: note: in instantiation of template class
’std::unordered_set, std::allocator
>’ requested here
std::unordered_set coll;
^
errornovel2.cpp:22:17: note: candidate function not viable: ’this’
argument has type ’const
MyCustomerHash’, but method is not marked const
std::size_t operator() (const Customer& c) {
^

Note that clang here mentions default template parameters such as
std::allocator, while gcc skips them.
As you can see, it is often helpful to have more than one compiler available to
test your code. Not only does it help you write more portable code, but where
one compiler produces a particularly inscrutable error message, another might
provide more insight.

9.5 Afternotes
The organization of source code in header files and CPP files is a practical
consequence of various incarnations of the one-definition rule or ODR. An
extensive discussion of this rule is presented in Appendix A.
The inclusion model is a pragmatic answer dictated largely by existing
practice in C++ compiler implementations. However, the first C++
implementation was different: The inclusion of template definitions was implicit,
which created a certain illusion of separation (see Chapter 14 for details on this
original model).
The first C++ standard ([C++98]) provided explicit support for the separation
model of template compilation via exported templates. The separation model
allowed template declarations marked as export to be declared in headers,
while their corresponding definitions were placed in CPP files, much like
declarations and definitions for nontemplate code. Unlike the inclusion model,
this model was a theoretical model not based on any existing implementation,
and the implementation itself proved far more complicated than the C++
standardization committee had anticipated. It took more than five years to see its
first implementation published (May 2002), and no other implementations
appeared in the years since. To better align the C++ standard with existing
practice, the C++ standardization committee removed exported templates from
C++11. Readers interested in learning more about the details (and pitfalls) of the

separation model are encouraged to read Sections 6.3 and 10.3 of the first edition
of this book ([VandevoordeJosuttisTemplates1st]).
It is sometimes tempting to imagine ways of extending the concept of
precompiled headers so that more than one header could be loaded for a single
compilation. This would in principle allow for a finer grained approach to
precompilation. The obstacle here is mainly the preprocessor: Macros in one
header file can entirely change the meaning of subsequent header files. However,
once a file has been precompiled, macro processing is completed, and it is hardly
practical to attempt to patch a precompiled header for the preprocessor effects
induced by other headers. A new language feature known as modules (see
Section 17.11 on page 366) is expected to be added to C++ in the not too distant
future to address this issue (macro definitions cannot leak into module
interfaces).

9.6 Summary
• The inclusion model of templates is the most widely used model for organizing
template code. Alternatives are discussed in Chapter 14.
• Only full specializations of function templates need inline when defined in
header files outside classes or structures.
• To take advantage of precompiled headers, be sure to keep the same order for
#include directives.
• Debugging code with templates can be challenging.
1

With some implementations this string is mangled (encoded with types of
arguments and names of surrounding scopes to distinguish it from other
names), but a demangler is available to turn it into human-readable text.
2 In theory, the standard headers do not actually need to correspond to physical
files. In practice, however, they do, and the files are very large.

Chapter 10
Basic Template Terminology
So far we have introduced the basic concept of templates in C++. Before we go
into details, let’s look at the terminology we use. This is necessary because,
inside the C++ community (and even in an early version of the standard), there is
sometimes a lack of precision regarding terminology.

10.1 “Class Template” or “Template Class”?
In C++, structs, classes, and unions are collectively called class types. Without
additional qualification, the word “class” in plain text type is meant to include
class types introduced with either the keyword class or the keyword
struct.1 Note specifically that “class type” includes unions, but “class” does
not.
There is some confusion about how a class that is a template is called: • The
term class template states that the class is a template. That is, it is a
parameterized description of a family of classes.
• The term template class, on the other hand, has been used – as a synonym for
class template.
– to refer to classes generated from templates.
– to refer to classes with a name that is a template-id (the combination of a
template name followed by the template arguments specified between < and
>).
The difference between the second and third meanings is somewhat subtle
and unimportant for the remainder of the text.
Because of this imprecision, we avoid the term template class in this book.
Similarly, we use function template, member template, member function
template, and variable template but avoid template function, template member,
template member function, and template variable.

10.2 Substitution, Instantiation, and Specialization
When processing source code that uses templates, a C++ compiler must at
various times substitute concrete template arguments for the template parameters
in the template. Sometimes, this substitution is just tentative: The compiler may
need to check if the substitution could be valid (see Section 8.4 on page 129 and
Section 15.7 on page 284).
The process of actually creating a definition for a regular class, type alias,
function, member function, or variable from a template by substituting concrete
arguments for the template parameters is called template instantiation.
Surprisingly, there is currently no standard or generally agreed upon term to
denote the process of creating a declaration that is not a definition through
template parameter substitution. We have seen the phrases partial instantiation
or instantiation of a declaration used by some teams, but those are by no means
universal. Perhaps a more intuitive term is incomplete instantiation (which, in
the case of a class template, produces an incomplete class).
The entity resulting from an instantiation or an incomplete instantiation (i.e., a
class, function, member function, or variable) is generically called a
specialization.
However, in C++ the instantiation process is not the only way to produce a
specialization. Alternative mechanisms allow the programmer to specify
explicitly a declaration that is tied to a special substitution of template
parameters. As we showed in Section 2.5 on page 31, such a specialization is
introduced with the prefix template<>: Click here to view code image
template // primary class template
class MyClass {
…
};
template<> // explicit specialization
class MyClass {
…
};

Strictly speaking, this is called an explicit specialization (as opposed to an
instantiated or generated specialization).
As described in Section 2.6 on page 33, specializations that still have template
parameters are called partial specializations: Click here to view code image
template // partial specialization
class MyClass {
…

};
template // partial specialization
class MyClass {
…
};

When talking about (explicit or partial) specializations, the general template is
also called the primary template.

10.3 Declarations versus Definitions
So far, the words declaration and definition have been used only a few times in
this book. However, these words carry with them a rather precise meaning in
standard C++, and that is the meaning that we use.
A declaration is a C++ construct that introduces or reintroduces a name into a
C++ scope. This introduction always includes a partial classification of that
name, but the details are not required to make a valid declaration. For example:
Click here to view code image
class C; // a declaration of C as a class
void f(int p); // a declaration of f() as a function and p as a named
parameter
extern int v; // a declaration of v as a variable

Note that even though they have a “name,” macro definitions and goto labels
are not considered declarations in C++.
Declarations become definitions when the details of their structure are made
known or, in the case of variables, when storage space must be allocated. For
class type definitions, this means a brace-enclosed body must be provided. For
function definitions, this means a brace-enclosed body must be provided (in the
common case), or the function must be designated as = default2 or =
delete. For a variable, initialization or the absence of an extern specifier
causes a declaration to become a definition. Here are examples that complement
the preceding nondefinition declarations: Click here to view code image
class C {}; // definition (and declaration) of class C
void f(int p) { //definition (and declaration) of function f()
std::cout << p << ’\n’;
}
extern int v = 1; // an initializer makes this a definition for v
int w; // global variable declarations not preceded by
// extern are also definitions

By extension, the declaration of a class template or function template is called a
definition if it has a body. Hence, Click here to view code image
template
void func (T); is a declaration that is not a definition, whereas
Click here to view code image
template
class S {}; is in fact a definition.

10.3.1 Complete versus Incomplete Types
Types can be complete or incomplete, which is a notion closely related to the
distinction between a declaration and a definition. Some language constructs
require complete types, whereas others are valid with incomplete types too.
Incomplete types are one of the following: • A class type that has been
declared but not yet defined.
• An array type with an unspecified bound.
• An array type with an incomplete element type.
• void
• An enumeration type as long as the underlying type or the enumeration values
are not defined.
• Any type above to which const and/or volatile are applied. All other
types are complete. For example: Click here to view code image
class C; // C is an incomplete type
C const* cp; // cp is a pointer to an incomplete type
extern C elems[10]; // elems has an incomplete type
extern int arr[]; // arr has an incomplete type
…
class C { }; // C now is a complete type (and therefore cpand elems
// no longer refer to an incomplete type)
int arr[10]; // arr now has a complete type

See Section 11.5 on page 171 for hints about how to deal with incomplete types
in templates.

10.4 The One-Definition Rule
The C++ language definition places some constraints on the redeclaration of
various entities. The totality of these constraints is known as the one-definition

rule or ODR. The details of this rule are a little complex and span a large variety
of situations. Later chapters illustrate the various resulting facets in each
applicable context, and you can find a complete description of the ODR in
Appendix A. For now, it suffices to remember the following ODR basics: •
Ordinary (i.e., not templates) noninline functions and member functions, as well
as (noninline) global variables and static data members should be defined only
once across the whole program.3
• Class types (including structs and unions), templates (including partial
specializations but not full specializations), and inline functions and variables
should be defined at most once per translation unit, and all these definitions
should be identical.
A translation unit is what results from preprocessing a source file; that is, it
includes the contents named by #include directives and produced by macro
expansions.
In the remainder of this book, linkable entity refers to any of the following: a
function or member function, a global variable or a static data member, including
any such things generated from a template, as visible to the linker.

10.5 Template Arguments versus Template
Parameters
Compare the following class template: Click here to view code image
template
class ArrayInClass {
public:
T array[N];
};

with a similar plain class: Click here to view code image
class DoubleArrayInClass {
public:
double array[10];
};

The latter becomes essentially equivalent to the former if we replace the
parameters T and N by double and 10 respectively. In C++, the name of this
replacement is denoted as ArrayInClass
Note how the name of the template is followed by template arguments in angle

brackets.
Regardless of whether these arguments are themselves dependent on template
parameters, the combination of the template name, followed by the arguments in
angle brackets, is called a template-id.
This name can be used much like a corresponding nontemplate entity would
be used. For example: Click here to view code image
int main()
{
ArrayInClass
ad; ad.array[0] = 1.0;
}

It is essential to distinguish between template parameters and template
arguments. In short, you can say that “parameters are initialized by arguments.”4
Or more precisely: • Template parameters are those names that are listed after
the keyword template in the template declaration or definition (T and N in our
example).
• Template arguments are the items that are substituted for template parameters
(double and 10 in our example). Unlike template parameters, template
arguments can be more than just “names.”
The substitution of template parameters by template arguments is explicit when
indicated with a template-id, but there are various situations when the
substitution is implicit (e.g., if template parameters are substituted by their
default arguments).
A fundamental principle is that any template argument must be a quantity or
value that can be determined at compile time. As becomes clear later, this
requirement translates into dramatic benefits for the run-time costs of template
entities. Because template parameters are eventually substituted by compile-time
values, they can themselves be used to form compile-time expressions. This was
exploited in the ArrayInClass template to size the member array array.
The size of an array must be a constant-expression, and the template parameter N
qualifies as such.
We can push this reasoning a little further: Because template parameters are
compile-time entities, they can also be used to create valid template arguments.
Here is an example: Click here to view code image
template
class Dozen {
public:
ArrayInClass contents;
};

Note how in this example the name T is both a template parameter and a
template argument. Thus, a mechanism is available to enable the construction of
more complex templates from simpler ones. Of course, this is not fundamentally
different from the mechanisms that allow us to assemble types and functions.

10.6 Summary
• Use class template, function template, and variable template for classes,
functions, and variables, respectively, that are templates.
• Template instantiation is the process of creating regular classes or functions by
replacing template parameters with concrete arguments. The resulting entity is
a specialization.
• Types can be complete or incomplete.
• According to the one-definition rule (ODR), noninline functions, member
functions, global variables, and static data members should be defined only
once across the whole program.
1

In C++, the only difference between class and struct is that the default
access for class is private, whereas the default access for struct is
public. However, we prefer to use class for types that use new C++
features, and we use struct for ordinary C data structure that can be used as
“plain old data” (POD).
2 Defaulted functions are special member functions that will be given a default
implementation by the compiler, such as the default copy constructor.
3 Global and static variables and data members can be defined as inline since
C++17. This removes the requirement that they be defined in exactly one
translation unit.
4 In the academic world, arguments are sometimes called actual parameters,
whereas parameters are called formal parameters.

Chapter 11
Generic Libraries
So far, our discussion of templates has focused on their specific features,
capabilities, and constraints, with immediate tasks and applications in mind (the
kind of things we run into as application programmers). However, templates are
most effective when used to write generic libraries and frameworks, where our
designs have to consider potential uses that are a priori broadly unconstrained.
While just about all the content in this book can be applicable to such designs,
here are some general issues you should consider when writing portable
components that you intend to be usable for as-yet unimagined types.
The list of issues raised here is not complete in any sense, but it summarizes
some of the features introduced so far, introduces some additional features, and
refers to some features covered later in this book. We hope it will also be a great
motivator to read through the many chapters that follow.

11.1 Callables
Many libraries include interfaces to which client code passes an entity that must
be “called.” Examples include an operation that must be scheduled on another
thread, a function that describes how to hash values to store them in a hash table,
an object that describes an order in which to sort elements in a collection, and a
generic wrapper that provides some default argument values. The standard
library is no exception here: It defines many components that take such callable
entities.
One term used in this context is callback. Traditionally that term has been
reserved for entities that are passed as function call arguments (as opposed to,
e.g., template arguments), and we maintain this tradition. For example, a sort
function may include a callback parameter as “sorting criterion,” which is called
to determine whether one element precedes another in the desired sorted order.
In C++, there are several types that work well for callbacks because they can
both be passed as function call arguments and can be directly called with the
syntax f(… ): • Pointer-to-function types

• Class types with an overloaded operator() (sometimes called functors),
including lambdas • Class types with a conversion function yielding a pointerto-function or reference-to-function Collectively, these types are called
function object types, and a value of such a type is a function object. 157
The C++ standard library introduces the slightly broader notion of a callable
type, which is either a function object type or a pointer to member. An object of
callable type is a callable object, which we refer to as a callable for
convenience.
Generic code often benefits from being able to accept any kind of callable,
and templates make it possible to do so.

11.1.1 Supporting Function Objects
Let’s look how the for_each() algorithm of the standard library is
implemented (using our own name “foreach” to avoid name conflicts and for
simplicity skipping returning anything): Click here to view code image
basics/foreach.hpp
template
void foreach (Iter current, Iter end, Callable op)
{
while (current != end) { //as long as not reached the end
op(*current); // call passed operator for current element
++current; // and move iterator to next element
}
}

The following program demonstrates the use of this template with various
function objects: Click here to view code image
basics/foreach.cpp
#include 
#include 
#include "foreach.hpp"
// a function to call:
void func(int i)
{ std::cout << "func() called for: " << i << ’\n’;
}
// a function object type (for objects that can be used as functions):

class FuncObj {
public:
void operator() (int i) const { //Note: const member function
std::cout << "FuncObj::op() called for: " << i << ’\n’;
}
};
int main()
{
std::vector primes = { 2, 3, 5, 7, 11, 13, 17, 19 };
foreach(primes.begin(), primes.end(), // range
func); // function as callable (decays to pointer)
foreach(primes.begin(), primes.end(), // range
&func); // function pointer as callable
foreach(primes.begin(), primes.end(), // range
FuncObj()); // function object as callable
foreach(primes.begin(), primes.end(), // range
[] (int i) { //lambda as callable
std::cout << "lambda called for: " << i << ’\n’;
});
}

Let’s look at each case in detail: • When we pass the name of a function as a
function argument, we don’t really pass the function itself but a pointer or
reference to it. As with arrays (see Section 7.4 on page 115), function arguments
decay to a pointer when passed by value, and in the case of a parameter whose
type is a template parameter, a pointer-to-function type will be deduced.
Just like arrays, functions can be passed by reference without decay.
However, function types cannot really be qualified with const. If we were to
declare the last parameter of foreach() with type Callable const&,
the const would just be ignored. (Generally speaking, references to functions
are rarely used in mainstream C++ code.) • Our second call explicitly takes a
function pointer by passing the address of a function name. This is equivalent
to the first call (where the function name implicitly decayed to a pointer value)
but is perhaps a little clearer.
• When passing a functor, we pass a class type object as a callable. Calling
through a class type usually amounts to invoking its operator(). So the call
op(*current);
is usually transformed into
Click here to view code image
op.operator()(*current); // call operator() with parameter
*current for op

Note that when defining operator(), you should usually define it as a

constant member function. Otherwise, subtle error messages can occur when
frameworks or libraries expect this call not to change the state of the passed
object (see Section 9.4 on page 146 for details).
It is also possible for a class type object to be implicitly convertible to a
pointer or reference to a surrogate call function (discussed in Section C.3.5 on
page 694). In such a case, the call op(*current);
would be transformed into
(op.operator F())(*current);

where F is the type of the pointer-to-function or reference-to-function that the
class type object can be converted to. This is relatively unusual.
• Lambda expressions produce functors (called closures), and therefore this case
is not different from the functor case. Lambdas are, however, a very
convenient shorthand notation to introduce functors, and so they appear
commonly in C++ code since C++11.
Interestingly, lambdas that start with [] (no captures) produce a conversion
operator to a function pointer. However, that is never selected as a surrogate
call function because it is always a worse match than the normal
operator() of the closure.

11.1.2 Dealing with Member Functions and Additional
Arguments
One possible entity to call was not used in the previous example: member
functions. That’s because calling a nonstatic member function normally involves
specifying an object to which the call is applied using syntax like
object.memfunc(… ) or ptr->memfunc(… ) and that doesn’t match
the usual pattern function-object(… ).
Fortunately, since C++17, the C++ standard library provides a utility
std::invoke() that conveniently unifies this case with the ordinary
function-call syntax cases, thereby enabling calls to any callable object with a
single form. The following implementation of our foreach() template uses
std::invoke(): Click here to view code image
basics/foreachinvoke.hpp
#include 

#include 
template
void foreach (Iter current, Iter end, Callable op, Args const&… args)
{
while (current != end) { //as long as not reached the end of the
elements
std::invoke(op, //call passed callable with
args…, //any additional args
*current); // and the current element
++current;
}
}

Here, besides the callable parameter, we also accept an arbitrary number of
additional parameters. The foreach() template then calls std::invoke()
with the given callable followed by the additional given parameters along with
the referenced element. std::invoke() handles this as follows: • If the
callable is a pointer to member, it uses the first additional argument as the this
object. All remaining additional parameters are just passed as arguments to the
callable.
• Otherwise, all additional parameters are just passed as arguments to the
callable.
Note that we can’t use perfect forwarding here for the callable or additional
parameters: The first call might “steal” their values, leading to unexpected
behavior calling op in subsequent iterations.
With this implementation, we can still compile our original calls to
foreach() above. Now, in addition, we can also pass additional arguments to
the callable and the callable can be a member function.1 The following client
code illustrates this: Click here to view code image
basics/foreachinvoke.cpp
#include
#include
#include
#include




"foreachinvoke.hpp"

// a class with a member function that shall be called
class MyClass {
public:
void memfunc(int i) const {
std::cout << "MyClass::memfunc() called for: " << i << ’\n’;
}
};

int main()
{
std::vector primes = { 2, 3, 5, 7, 11, 13, 17, 19 };
// pass lambda as callable and an additional argument:
foreach(primes.begin(), primes.end(), //elements for 2nd arg of lambda
[](std::string const& prefix, int i) { //lambda to call
std::cout << prefix << i << ’\n’;
},
"- value:"); //1st arg of lambda
// call obj.memfunc() for/with each elements in primes passed as
argument
MyClass obj;
foreach(primes.begin(), primes.end(), //elements used as args
&MyClass::memfunc, //member function to call
obj); // object to call memfunc() for
}

The first call of foreach() passes its fourth argument (the string literal "value: ") to the first parameter of the lambda, while the current element in
the vector binds to the second parameter of the lambda. The second call passes
the member function memfunc() as the third argument to be called for obj
passed as the fourth argument.
See Section D.3.1 on page 716 for type traits that yield whether a callable can
be used by std::invoke().

11.1.3 Wrapping Function Calls
A common application of std::invoke() is to wrap single function calls
(e.g., to log the calls, measure their duration, or prepare some context such as
starting a new thread for them). Now, we can support move semantics by perfect
forwarding both the callable and all passed arguments: Click here to view code
image
basics/invoke.hpp
#include  // for std::invoke()
#include  // for std::forward()
template
decltype(auto) call(Callable&& op, Args&&… args)
{

return std::invoke(std::forward(op), //passed callable with
std::forward(args)…); // any additional args
}

The other interesting aspect is how to deal with the return value of a called
function to “perfectly forward” it back to the caller. To support returning
references (such as a std::ostream&) you have to use decltype(auto)
instead of just auto: Click here to view code image
template
decltype(auto) call(Callable&& op, Args&&… args) decltype(auto)
(available since C++14) is a placeholder type that determines the
type of variable, return type, or template argument from the type of
the associated expression (initializer, return value, or template
argument). See Section 15.10.3 on page 301 for details.

If you want to temporarily store the value returned by std::invoke() in a
variable to return it after doing something else (e.g., to deal with the return value
or log the end of the call), you also have to declare the temporary variable with
decltype(auto): Click here to view code image
decltype(auto) ret{std::invoke(std::forward(op),
std::forward(args)…)};
…
return ret; Note that declaring ret with auto&& is not correct. As a
reference, auto&& extends the lifetime of the returned value until
the end of its scope (see Section 11.3 on page 167) but not beyond
the return statement to the caller of the function.

However, there is also a problem with using decltype(auto): If the
callable has return type void, the initialization of ret as decltype(auto)
is not allowed, because void is an incomplete type. You have the following
options: • Declare an object in the line before that statement, whose destructor
performs the observable behavior that you want to realize. For example:2
Click here to view code image
struct cleanup {
~cleanup() {
… //code to perform on return
}
} dummy;
return std::invoke(std::forward(op),
std::forward(args)…);

• Implement the void and non-void cases differently: Click here to view code
image
basics/invokeret.hpp

#include  // for std::invoke()
#include  // for std::forward()
#include  // for std::is_same<> and invoke_result<>
template
decltype(auto) call(Callable&& op, Args&&… args)
{
if constexpr(std::is_same_v,
void>) {
// return type is void:
std::invoke(std::forward(op),
std::forward(args)…);
…
return;
}
else {
// return type is not void:
decltype(auto) ret{std::invoke(std::forward(op),
std::forward(args)…)};
…
return ret;
}
}

With
Click here to view code image
if constexpr(std::is_same_v,
void>) we test at compile time whether the return type of calling
callable with Args… is void. See Section D.3.1 on page 717 for
details about std::invoke_result<>.3

Future C++ versions might hopefully avoid the need for such as special handling
of void (see Section 17.7 on page 361).

11.2 Other Utilities to Implement Generic Libraries
std::invoke() is just one example of useful utilities provided by the C++
standard library for implementing generic libraries. In what follows, we survey
some other important ones.

11.2.1 Type Traits

The standard library provides a variety of utilities called type traits that allow us
to evaluate and modify types. This supports various cases where generic code
has to adapt to or react on the capabilities of the types for which they are
instantiated. For example: Click here to view code image
#include 
template
class C
{
// ensure that T is not void (ignoring const or volatile):
static_assert(!std::is_same_v,void>,
"invalid instantiation of class C for void type");
public:
template
void f(V&& v) {
if constexpr(std::is_reference_v) {
… // special code if T is a reference type
}
if constexpr(std::is_convertible_v,T>) {
… // special code if V is convertible to T
}
if constexpr(std::has_virtual_destructor_v) {
… // special code if V has virtual destructor
}
}
};

As this example demonstrates, by checking certain conditions we can choose
between different implementations of the template. Here, we use the compiletime if feature, which is available since C++17 (see Section 8.5 on page 134),
but we could have used std::enable_if, partial specialization, or SFINAE
to enable or disable helper templates instead (see Chapter 8 for details).
However, note that type traits must be used with particular care: They might
behave differently than the (naive) programmer might expect. For example:
Click here to view code image
std::remove_const_t // yields int const&

Here, because a reference is not const (although you can’t modify it), the call
has no effect and yields the passed type.
As a consequence, the order of removing references and const matters:
Click here to view code image
std::remove_const_t> // int
std::remove_reference_t> // int const

Instead, you might call just Click here to view code image

std::decay_t // yields int

which, however, would also convert raw arrays and functions to the
corresponding pointer types.
Also there are cases where type traits have requirements. Not satisfying those
requirements results in undefined behavior.4 For example: Click here to view
code image
make_unsigned_t // unsigned int
make_unsigned_t // undefined behavior (hopefully error)

Sometimes the result may be surprising. For example: Click here to view code
image
add_rvalue_reference_t // int&&
add_rvalue_reference_t // int const&&
add_rvalue_reference_t // int const& (lvalue-ref remains
lvalue-ref)

Here we might expect that add_rvalue_reference always results in an
rvalue reference, but the reference-collapsing rules of C++ (see Section 15.6.1
on page 277) cause the combination of an lvalue reference and rvalue reference
to produce an lvalue reference.
As another example:
Click here to view code image
is_copy_assignable_v // yields true (generally, you can assign
an int to an int)
is_assignable_v // yields false (can’t call 42 = 42)

While is_copy_assignable just checks in general whether you can assign
ints to another (checking the operation for lvalues), is_assignable takes
the value category (see Appendix B) into account (here checking whether you
can assign a prvalue to a prvalue). That is, the first expression is equivalent to
Click here to view code image
is_assignable_v // yields true

For the same reason:
Click here to view code image
is_swappable_v // yields true (assuming lvalues)
is_swappable_v // yields true (equivalent to the previous
check)
is_swappable_with_v // yields false (taking value category
into account)

For all these reasons, carefully note the exact definition of type traits. We

describe the standard ones in detail in Appendix D.

11.2.2 std::addressof()
The std::addressof<>() function template yields the actual address of an
object or function. It works even if the object type has an overloaded operator &.
Even though the latter is somewhat rare, it might happen (e.g., in smart pointers).
Thus, it is recommended to use addressof() if you need an address of an
object of arbitrary type: Click here to view code image
template
void f (T&& x)
{
auto p = &x; // might fail with overloaded operator &
auto q = std::addressof(x); // works even with overloaded operator &
…
}

11.2.3 std::declval()
The std::declval<>() function template can be used as a placeholder for
an object reference of a specific type. The function doesn’t have a definition and
therefore cannot be called (and doesn’t create an object). Hence, it can only be
used in unevaluated operands (such as those of decltype and sizeof
constructs). So, instead of trying to create an object, you can assume you have an
object of the corresponding type.
For example, the following declaration deduces the default return type RT
from the passed template parameters T1 and T2: Click here to view code image
basics/maxdefaultdeclval.hpp
#include 
template()
: std::declval())>>
RT max (T1 a, T2 b)
{
return b < a ? a : b;
}

To avoid that we have to call a (default) constructor for T1 and T2 to be able to
call operator ?: in the expression to initialize RT, we use std::declval to
“use” objects of the corresponding type without creating them. This is only
possible in the unevaluated context of decltype, though.
Don’t forget to use the std::decay<> type trait to ensure the default return
type can’t be a reference, because std::declval() itself yields rvalue
references. Otherwise, calls such as max(1, 2) will get a return type of
int&&.5 See Section 19.3.4 on page 415 for details.

11.3 Perfect Forwarding Temporaries
As shown in Section 6.1 on page 91, we can use forwarding references and
std::forward<> to “perfectly forward” generic parameters: Click here to
view code image
template
void f (T&& t) // t is forwarding reference
{
g(std::forward(t)); // perfectly forward passed argument t to g()
}

However, sometimes we have to perfectly forward data in generic code that does
not come through a parameter. In that case, we can use auto&& to create a
variable that can be forwarded. Assume, for example, that we have chained calls
to functions get() and set() where the return value of get() should be
perfectly forwarded to set(): Click here to view code image
template
void foo(T x)
{
set(get(x));
}

Suppose further that we need to update our code to perform some operation on
the intermediate value produced by get(). We do this by holding the value in a
variable declared with auto&&: Click here to view code image
template
void foo(T x)
{
auto&& val = get(x);
…
// perfectly forward the return value of get() to set():
set(std::forward(val));

}

This avoids extraneous copies of the intermediate value.

11.4 References as Template Parameters
Although it is not common, template type parameters can become reference
types. For example: Click here to view code image
basics/tmplparamref.cpp
#include 
template
void tmplParamIsReference(T) {
std::cout << "T is reference: " << std::is_reference_v << ’\n’;
}
int main()
{
std::cout << std::boolalpha;
int i;
int& r = i;
tmplParamIsReference(i); // false
tmplParamIsReference(r); // false
tmplParamIsReference(i); // true
tmplParamIsReference(r); // true
}

Even if a reference variable is passed to tmplParamIsReference(), the
template parameter T is deduced to the type of the referenced type (because, for
a reference variable v, the expression v has the referenced type; the type of an
expression is never a reference). However, we can force the reference case by
explicitly specifying the type of T: tmplParamIsReference(r);
tmplParamIsReference(i); Doing this can fundamentally change the
behavior of a template, and, as likely as not, a template may not have been
designed with this possibility in mind, thereby triggering errors or unexpected
behavior. Consider the following example: Click here to view code image
basics/referror1.cpp
template
class RefMem {
private:
T zero;
public:

RefMem() : zero{Z} {
}
};
int null = 0;
int main()
{
RefMem rm1, rm2;
rm1 = rm2; // OK
RefMem rm3; // ERROR: invalid default value for N
RefMem rm4; // ERROR: invalid default value for N
extern int null;
RefMem rm5, rm6;
rm5 = rm6; // ERROR: operator= is deleted due to reference member
}

Here we have a class with a member of template parameter type T, initialized
with a nontype template parameter Z that has a zero-initialized default value.
Instantiating the class with type int works as expected. However, when trying
to instantiate it with a reference, things become tricky: • The default
initialization no longer works.
• You can no longer pass just 0 as initializer for an int.
• And, perhaps most surprising, the assignment operator is no longer available
because classes with nonstatic reference members have deleted default
assignment operators.
Also, using reference types for nontype template parameters is tricky and can be
dangerous. Consider this example: Click here to view code image
basics/referror2.cpp
#include 
#include 
template // Note: size is reference
class Arr {
private:
std::vector elems;
public:
Arr() : elems(SZ) { //use current SZ as initial vector size
}
void print() const {
for (int i=0; i y; // compile-time ERROR deep in the code of class
std::vector<>
Arr x; // initializes internal vector with 10 elements
x.print(); // OK
size += 100; // OOPS: modifies SZ in Arr<>
x.print(); // run-time ERROR: invalid memory access: loops over 120
elements
}

Here, the attempt to instantiate Arr for elements of a reference type results in an
error deep in the code of class std::vector<>, because it can’t be
instantiated with references as elements: Click here to view code image
Arr y; // compile-time ERROR deep in the code of class
std::vector<>

The error often leads to the “error novel” described in Section 9.4 on page 143,
where the compiler provides the entire template instantiation history from the
initial cause of the instantiation down to the actual template definition in which
the error was detected.
Perhaps worse is the run-time error resulting from making the size parameter a
reference: It allows the recorded size value to change without the container being
aware of it (i.e., the size value can become invalid). Thus, operations using the
size (like the print() member) are bound to run into undefined behavior
(causing the program to crash, or worse): Click here to view code image
int int size = 10;
…
Arr x; // initializes internal vector with 10 elements
size += 100; // OOPS: modifies SZ in Arr<>
x.print(); // run-time ERROR: invalid memory access: loops over 120
elements

Note that changing the template parameter SZ to be of type int const& does
not address this issue, because size itself is still modifiable.
Arguably, this example is far-fetched. However, in more complex situations,
issues like these do occur. Also, in C++17 nontype parameters can be deduced;
for example: Click here to view code image
template
class Arr; Using decltype(auto) can easily produce reference types

and is therefore generally avoided in this context (use auto by
default). See Section 15.10.3 on page 302 for details.

The C++ standard library for this reason sometimes has surprising
specifications and constraints. For example: • In order to still have an assignment
operator even if the template parameters are instantiated for references, classes
std::pair<> and std::tuple<> implement the assignment operator
instead of using the default behavior. For example: Click here to view code
image
namespace std {
template
struct pair {
T1 first;
T2 second;
…
// default copy/move constructors are OK even with references:
pair(pair const&) = default;
pair(pair&&) = default;
…
// but assignment operator have to be defined to be available with
references:
pair& operator=(pair const& p);
pair& operator=(pair&& p) noexcept(…);
…
};
}

• Because of the complexity of possible side effects, instantiation of the C++17
standard library class templates std::optional<> and
std::variant<> for reference types is ill-formed (at least in C++17).
To disable references, a simple static assertion is enough: Click here to view
code image
template
class optional
{
static_assert(!std::is_reference::value,
"Invalid instantiation of optional for references");
…
};

Reference types in general are quite unlike other types and are subject to several
unique language rules. This impacts, for example, the declaration of call
parameters (see Section 7 on page 105) and also the way we define type traits
(see Section 19.6.1 on page 432).

11.5 Defer Evaluations
When implementing templates, sometimes the question comes up whether the
code can deal with incomplete types (see Section 10.3.1 on page 154). Consider
the following class template: Click here to view code image
template
class Cont {
private:
T* elems;
public:
…
};

So far, this class can be used with incomplete types. This is useful, for example,
with classes that refer to elements of their own type: Click here to view code
image
struct Node
{
std::string value;
Cont next; // only possible if Cont accepts incomplete types
};

However, for example, just by using some traits, you might lose the ability to
deal with incomplete types. For example: Click here to view code image
template
class Cont {
private:
T* elems;
public:
…
typename std::conditional::value,
T&&,
T&
>::type
foo();
};

Here, we use the trait std::conditional (see Section D.5 on page 732) to
decide whether the return type of the member function foo() is T&& or T&.
The decision depends on whether the template parameter type T supports move
semantics.
The problem is that the trait std::is_move_constructible requires
that its argument is a complete type (and is not void or an array of unknown
bound; see Section D.3.2 on page 721). Thus, with this declaration of foo(),

the declaration of struct node fails.6
We can deal with this problem by replacing foo() by a member template so
that the evaluation of std::is_move_constructible is deferred to the
point of instantiation of foo(): Click here to view code image
template
class Cont {
private:
T* elems;
public:
template
typename std::conditional::value,
T&&,
T&
>::type
foo();
};

Now, the traits depends on the template parameter D (defaulted to T, the value
we want anyway) and the compiler has to wait until foo() is called for a
concrete type like Node before evaluating the traits (by then Node is a complete
type; it was only incomplete while being defined).

11.6 Things to Consider When Writing Generic
Libraries
Let’s list some things to remember when implementing generic libraries (note
that some of them might be introduced later in this book): • Use forwarding
references to forward values in templates (see Section 6.1 on page 91). If the
values do not depend on template parameters, use auto&& (see Section 11.3 on
page 167).
• When parameters are declared as forwarding references, be prepared that a
template parameter has a reference type when passing lvalues (see Section
15.6.2 on page 279).
• Use std::addressof() when you need the address of an object depending
on a template parameter to avoid surprises when it binds to a type with
overloaded operator& (Section 11.2.2 on page 166).
• For member function templates, ensure that they don’t match better than the
predefined copy/move constructor or assignment operator (Section 6.4 on page
99).

• Consider using std::decay when template parameters might be string
literals and are not passed by value (Section 7.4 on page 116 and Section D.4
on page 731).
• If you have out or inout parameters depending on template parameters, be
prepared to deal with the situation that const template arguments may be
specified (see, e.g., Section 7.2.2 on page 110).
• Be prepared to deal with the side effects of template parameters being
references (see Section 11.4 on page 167 for details and Section 19.6.1 on page
432 for an example). In particular, you might want to ensure that the return
type can’t become a reference (see Section 7.5 on page 117).
• Be prepared to deal with incomplete types to support, for example, recursive
data structures (see Section 11.5 on page 171).
• Overload for all array types and not just T[SZ] (see Section 5.4 on page 71).

11.7 Summary
• Templates allow you to pass functions, function pointers, function objects,
functors, and lambdas as callables.
• When defining classes with an overloaded operator(), declare it as const
(unless the call changes its state).
• With std::invoke(), you can implement code that can handle all callables,
including member functions.
• Use decltype(auto) to forward a return value perfectly.
• Type traits are type functions that check for properties and capabilities of types.
• Use std::addressof() when you need the address of an object in a
template.
• Use std::declval() to create values of specific types in unevaluated
expressions.
• Use auto&& to perfectly forward objects in generic code if their type does not
depend on template parameters.
• Be prepared to deal with the side effects of template parameters being
references.
• You can use templates to defer the evaluation of expressions (e.g., to support
using incomplete types in class templates).
1

std::invoke() also allows a pointer to data member as a callback type.

Instead of calling a function, it returns the value of the corresponding data
member in the object referred to by the additional argument.
2 Thanks to Daniel Krügler for pointing that out.
3 std::invoke_result<> is available since C++17. Since C++11, to get
the return type you could call: typename
std::result_of::type 4 There was a proposal for C++17 to
require that violations of preconditions of type traits must always result in a
compile-time error. However, because some type traits have over-constraining
requirements, such as always requiring complete types, this change was
postponed.
5 Thanks to Dietmar Kühl for pointing that out.
6 Not all compilers yield an error if std::is_move_constructible is
not an incomplete type. This is allowed, because for this kind of error, no
diagnostics is required. Thus, this is at least a portability problem.

Part II
Templates in Depth
The first part of this book provided a tutorial for most of the language concepts
underlying C++ templates. That presentation is sufficient to answer most
questions that may arise in everyday C++ programming. The second part of this
book provides a reference that answers even the more unusual questions that
arise when pushing the envelope of the language to achieve some advanced
software effects. If desired, you can skip this part on a first read and return to
specific topics as prompted by references in later chapters or after looking up a
concept in the index.
Our goal is to be clear and complete but also to keep the discussion concise.
To this end, our examples are short and often somewhat artificial. This also
ensures that we don’t stray from the topic at hand to unrelated issues.
In addition, we look at possible future changes and extensions for the
templates language feature in C++.
The topics of this part include: • Fundamental template declaration issues •
The meaning of names in templates • The C++ template instantiation
mechanisms • The template argument deduction rules • Specialization and
overloading • Future possibilities

Chapter 12
Fundamentals in Depth
In this chapter we review some of the fundamentals introduced in the first part of
this book in depth: the declaration of templates, the restrictions on template
parameters, the constraints on template arguments, and so forth.

12.1 Parameterized Declarations
C++ currently supports four fundamental kinds of templates: class templates,
function templates, variable templates, and alias templates. Each of these
template kinds can appear in namespace scope, but also in class scope. In class
scope they become nested class templates, member function templates, static
data member templates, and member alias templates. Such templates are
declared much like ordinary classes, functions, variables, and type aliases (or
their class member counterparts) except for being introduced by a
parameterization clause of the form template Note that
C++17 introduced another construct that is introduced with such a
parameterization clause: deduction guides (see Section 2.9 on page 42 and
Section 15.12.1 on page 314). Those aren’t called templates in this book (e.g.,
they are not instantiated), but the syntax was chosen to be reminiscent of
function templates.
We’ll come back to the actual template parameter declarations in a later
section. First, some examples illustrate the four kinds of templates. They can
occur in namespace scope (globally or in a namespace) as follows: Click here to
view code image
details/definitions1.hpp
template // a namespace scope class template
class Data {
public:
static constexpr bool copyable = true;
…
};

template // a namespace scope function template
void log (T x) {
…
}
template // a namespace scope variable template (since
C++14)
T zero = 0;
template // a namespace scope variable template (since
C++14)
bool dataCopyable = Data::copyable;
template // a namespace scope alias template
using DataList = Data; Note that in this example, the static data
member Data::copyable is not a variable template, even though it is
indirectly parameterized through the parameterization of the class
template Data. However, a variable template can appear in class scope
(as the next example will illustrate), and in that case it is a static
data member template.

The following example shows the four kinds of templates as class members
that are defined within their parent class: Click here to view code image
details/definitions2.hpp
class Collection {
public:
template // an in-class member class template definition
class Node {
…
};
template // an in-class (and therefore implicitly inline)
T* alloc() { //member function template definition
…
}
template // a member variable template (since C++14)
static T zero = 0;
template // a member alias template
using NodePtr = Node*;
};

Note that in C++17, variables—including static data members—and variable
templates can be “in-line,” which means that their definition can be repeated
across translation units. This is redundant for variable templates, which can
always be defined in multiple translation units. Unlike member functions,
however, a static data member being defined in its enclosing class does not make

it inline: The keyword inline must be specified in all cases.
Finally, the following code demonstrates how member templates that are not
alias templates can be defined out-of-class: Click here to view code image
details/definitions3.hpp
template // a namespace scope class template
class List {
public:
List() = default; // because a template constructor is defined
template // another member class template,
class Handle; // without its definition
template // a member function template
List (List const&); // (constructor)
template // a member variable template (since C++14)
static U zero;
};
template // out-of-class member class template definition
template
class List::Handle {
…
};
template // out-of-class member function template
definition
template
List::List (List const& b)
{
…
}
template // out-of-class static data member template
definition
template
U List::zero = 0;

Member templates defined outside their enclosing class may need multiple
template<… > parameterization clauses: one for every enclosing class
template and one for the member template itself. The clauses are listed starting
from the outermost class template.
Note also that a constructor template (a special kind of member function
template) disables the implicit declaration of the default constructor (because it
is only implicitly declared if no other constructor is declared). Adding a
defaulted declaration List() = default; ensures an instance of List is

default-constructible with the semantics of an implicitly declared constructor.
Union Templates
Union templates are possible too (and they are considered a kind of class
template): Click here to view code image
template
union AllocChunk {
T object;
unsigned char bytes[sizeof(T)];
};

Default Call Arguments
Function templates can have default call arguments just like ordinary function
declarations: Click here to view code image
template
void report_top (Stack const&, int number = 10);
template
void fill (Array&, T const& = T{}); // T{} is zero for built-in
types

The latter declaration shows that a default call argument could depend on a
template parameter. It also can be defined as (the only way possible before
C++11, see Section 5.2 on page 68) Click here to view code image
template
void fill (Array&, T const& = T()); // T() is zero for built-in
types

When the fill() function is called, the default argument is not instantiated if a
second function call argument is supplied. This ensures that no error is issued if
the default call argument cannot be instantiated for a particular T. For example:
Click here to view code image
class Value {
public:
explicit Value(int); // no default constructor
};
void init (Array& array)
{
Value zero(0);
fill(array, zero); // OK: default constructor not used

fill(array); // ERROR: undefined default constructor for Value is
used
}

Nontemplate Members of Class Templates
In addition to the four fundamental kinds of templates declared inside a class,
you can also have ordinary class members parameterized by being part of a class
template They are occasionally (erroneously) also referred to as member
templates. Although they can be parameterized, such definitions aren’t quite
first-class templates. Their parameters are entirely determined by the template of
which they are members. For example: Click here to view code image
template
class CupBoard
{
class Shelf; // ordinary class in class template
void open(); // ordinary function in class template
enum Wood : unsigned char; // ordinary enumeration type in class
template
static double totalWeight; // ordinary static data member in class
template
};

The corresponding definitions only specify a parameterization clause for the
parent class templates, but not for the member itself, because it is not a template
(i.e., no parameterization clause is associated with the name appearing after the
last ::): Click here to view code image
template // definition of ordinary class in class template
class CupBoard::Shelf {
…
};
template // definition of ordinary function in class template
void CupBoard::open()
{
…
}
template // definition of ordinary enumeration type class in
class template
enum CupBoard::Wood {
Maple, Cherry, Oak
};
template // definition of ordinary static member in class
template
double CupBoard::totalWeight = 0.0; Since C++17, the static

totalWeight member can be initialized inside the class template using
inline: Click here to view code image
template
class CupBoard
…
inline static double totalWeight = 0.0;
};

Although such parameterized definitions are commonly called templates, the
term doesn’t quite apply to them. A term that has been occasionally suggested
for these entities is temploid. Since C++17, the C++ standard does define the
notion of a templated entity, which includes templates and temploids as well as,
recursively, any entity defined or created in templated entities (that includes,
e.g., a friend function defined inside a class template (see Section 2.4 on page
30) or the closure type of a lambda expression appearing in a template). Neither
temploid nor templated entity has gained much traction so far, but they may be
useful terms to communicate more precisely about C++ templates in the future.

12.1.1 Virtual Member Functions
Member function templates cannot be declared virtual. This constraint is
imposed because the usual implementation of the virtual function call
mechanism uses a fixed-size table with one entry per virtual function. However,
the number of instantiations of a member function template is not fixed until the
entire program has been translated. Hence, supporting virtual member function
templates would require support for a whole new kind of mechanism in C++
compilers and linkers.
In contrast, the ordinary members of class templates can be virtual because
their number is fixed when a class is instantiated: Click here to view code image
template
class Dynamic {
public:
virtual ~Dynamic(); // OK: one destructor per instance of Dynamic
template
virtual void copy (T2 const&);
// ERROR: unknown number of instances of copy()
// given an instance of Dynamic
};

12.1.2 Linkage of Templates
Every template must have a name, and that name must be unique within its
scope, except that function templates can be overloaded (see Chapter 16). Note
especially that, unlike class types, class templates cannot share a name with a
different kind of entity: Click here to view code image
int C;
…
class C; // OK: class names and nonclass names are in a different
“space”
int X;
…
template
class X; // ERROR: conflict with variable X
struct S;
…
template
class S; // ERROR: conflict with struct S

Template names have linkage, but they cannot have C linkage. Nonstandard
linkages may have an implementation-dependent meaning (however, we don’t
know of an implementation that supports nonstandard name linkages for
templates): Click here to view code image
extern "C++" template
void normal(); //this is the default: the linkage specification could
be left out
extern "C" template
void invalid(); //ERROR: templates cannot have C linkage
extern "Java" template
void javaLink(); //nonstandard, but maybe some compiler will someday
// support linkage compatible with Java generics

Templates usually have external linkage. The only exceptions are namespace
scope function templates with the static specifier, templates that are direct or
indirect members of an unnamed name-space (which have internal linkage), and
member templates of unnamed classes (which have no linkage). For example:
Click here to view code image
template // refers to the same entity as a declaration of
the
void external(); // same name (and scope) in another file
template // unrelated to a template with the same name in
static void internal(); // another file

template // redeclaration of the previous declaration
static void internal();
namespace {
template // also unrelated to a template with the same name
void otherInternal(); // in another file, even one that similarly
appears
} //in an unnamed namespace
namespace {
template // redeclaration of the previous template
declaration
void otherInternal();
}
struct {
template void f(T) {} //no linkage: cannot be redeclared
} x;

Note that since the latter member template has no linkage, it must be defined
within the unnamed class because there is no way to provide a definition outside
the class.
Currently templates cannot be declared in function scope or local class scope,
but generic lambdas (see Section 15.10.6 on page 309), which have associated
closure types that contain member function templates, can appear in local
scopes, which effectively implies a kind of local member function template.
The linkage of an instance of a template is that of the template. For example, a
function internal() instantiated from the template internal
declared above will have internal linkage. This has an interesting consequence in
the case of variable templates. Indeed, consider the following example: Click
here to view code image
template T zero = T{}; All instantiations of zero have
external linkage, even something like zero. That’s perhaps
counterintuitive given that int const zero_int = int{}; has internal
linkage because it is declared with a const type. Similarly, all
instantiations of the template Click here to view code image
template int const max_volume = 11; have external
linkage, despite all those instantiations also having type int const.

12.1.3 Primary Templates
Normal declarations of templates declare primary templates. Such template
declarations are declared without adding template arguments in angle brackets

after the template name: Click here to view code image
template class Box; // OK: primary template
template class Box; // ERROR: does not specialize
template void translate(T); // OK: primary template
template void translate(T); // ERROR: not allowed for
functions
template constexpr T zero = T{}; // OK: primary template
template constexpr T zero = T{}; // ERROR: does not
specialize

Nonprimary templates occur when declaring partial specializations of class or
variable templates. Those are discussed in Chapter 16. Function templates must
always be primary templates (see Section 17.3 on page 356 for a discussion of a
potential future language change).

12.2 Template Parameters
There are three basic kinds of template parameters:
1. Type parameters (these are by far the most common) 2. Nontype parameters 3.
Template template parameters Any of these basic kinds of template
parameters can be used as the basis of a template parameter pack (see Section
12.2.4 on page 188).
Template parameters are declared in the introductory parameterization clause
of a template declaration.1 Such declarations do not necessarily need to be
named: Click here to view code image
template
class X; // X<> is parameterized by a type and an integer

A parameter name is, of course, required if the parameter is referred to later in
the template. Note also that a template parameter name can be referred to in a
subsequent parameter declaration (but not before): Click here to view code
image
template class Buf> // in the declaration of the third one
class Structure;

12.2.1 Type Parameters

Type parameters are introduced with either the keyword typename or the
keyword class: The two are entirely equivalent.2 The keyword must be
followed by a simple identifier, and that identifier must be followed by a comma
to denote the start of the next parameter declaration, a closing angle bracket (>)
to denote the end of the parameterization clause, or an equal sign (=) to denote
the beginning of a default template argument.
Within a template declaration, a type parameter acts much like a type alias (see
Section 2.8 on page 38). For example, it is not possible to use an elaborated
name of the form class T when T is a template parameter, even if T were to
be substituted by a class type: Click here to view code image
template
class List {
class Allocator* allocptr; // ERROR: use “Allocator* allocptr”
friend class Allocator; // ERROR: use “friend Allocator”
…
};

12.2.2 Nontype Parameters
Nontype template parameters stand for constant values that can be determined at
compile or link time.3 The type of such a parameter (in other words, the type of
the value for which it stands) must be one of the following: • An integer type or
an enumeration type
• A pointer type4
• A pointer-to-member type
• An lvalue reference type (both references to objects and references to functions
are acceptable) • std::nullptr_t
• A type containing auto or decltype(auto) (since C++17 only; see
Section 15.10.1 on page 296) All other types are currently excluded (although
floating-point types may be added in the future; see Section 17.2 on page 356).
Perhaps surprisingly, the declaration of a nontype template parameter can in
some cases also start with the keyword typename: Click here to view code
image
template // a nontype parameter
class List; or with the keyword class: Click here to view code image
template // a nontype parameter of pointer type
class Y; The two cases are easily distinguished because the first is

followed by a simple identifier and then one of a small set of tokens
(’=’ for a default argument, ’,’ to indicate that another template
parameter follows, or a closing > to end the template parameter
list). Section 5.1 on page 67 and Section 13.3.2 on page 229 explain
the need for the keyword typename in the first nontype parameter.

Function and array types can be specified, but they are implicitly adjusted to
the pointer type to which they decay: Click here to view code image
template class Lexer; // buf is really an int*
template class Lexer; // OK: this is a redeclaration
template struct FuncWrap; // fun really has pointer to
// function type
template struct FuncWrap; // OK: this is a redeclaration

Nontype template parameters are declared much like variables, but they cannot
have nontype specifiers like static, mutable, and so forth. They can have
const and volatile qualifiers, but if such a qualifier appears at the
outermost level of the parameter type, it is simply ignored: Click here to view
code image
template class Buffer; // const is useless here
template class Buffer; // same as previous declaration

Finally, nonreference nontype parameters are always prvalues5 when used in
expressions. Their address cannot be taken, and they cannot be assigned to. A
nontype parameter of lvalue reference type, on the other hand, can be used to
denote an lvalue: Click here to view code image
template
struct LocalIncrement {
LocalIncrement() { Counter = Counter + 1; } //OK: reference to an
integer
~LocalIncrement() { Counter = Counter - 1; }
};

Rvalue references are not permitted.

12.2.3 Template Template Parameters
Template template parameters are placeholders for class or alias templates. They
are declared much like class templates, but the keywords struct and union
cannot be used: Click here to view code image
template class C> // OK
void f(C* p);

template struct C> // ERROR: struct not valid
here
void f(C* p);
template union C> // ERROR: union not valid here
void f(C* p); C++17 allows the use of typename instead of class:
That change was motivated by the fact that template template
parameters can be substituted not only by class templates but also by
alias templates (which instantiate to arbitrary types). So, in C++17,
our example above can be written instead as Click here to view code
image
template typename C> // OK since C++17
void f(C* p); In the scope of their declaration, template
template parameters are used just like other class or alias
templates.

The parameters of template template parameters can have default template
arguments. These default arguments apply when the corresponding parameters
are not specified in uses of the template template parameter: Click here to view
code image
template class Container>
class Adaptation {
Container storage; // implicitly equivalent to
Container
…
};

T and A are the names of the template parameter of the template template
parameter Container. These names be used only in the declaration of other
parameters of that template template parameter. The following contrived
template illustrates this concept: Click here to view code image
template class Buf> // OK
class Lexer {
static T* storage; // ERROR: a template template parameter cannot be
used here
…
};

Usually however, the names of the template parameters of a template template
parameter are not needed in the declaration of other template parameters and are
therefore often left unnamed altogether. For example, our earlier Adaptation
template could be declared as follows: Click here to view code image
template class Container>
class Adaptation {

Container storage; // implicitly equivalent to
Container
…
};

12.2.4 Template Parameter Packs
Since C++11, any kind of template parameter can be turned into a template
parameter pack by introducing an ellipsis (…) prior to the template parameter
name or, if the template parameter is unnamed, where the template parameter
name would occur: Click here to view code image
template // declares a template parameter pack named
Types
class Tuple; A template parameter pack behaves like its underlying
template parameter, but with a crucial difference: While a normal
template parameter matches exactly one template argument, a template
parameter pack can match any number of template arguments. This means
that the Tuple class template declared above accepts any number of
(possibly distinct) types as template arguments: Click here to view
code image
using IntTuple = Tuple; // OK: one template argument
using IntCharTuple = Tuple; // OK: two template arguments
using IntTriple = Tuple; // OK: three template
arguments
using EmptyTuple = Tuple<>; // OK: zero template arguments

Similarly, template parameter packs of nontype and template template
parameters can accept any number of nontype or template template arguments,
respectively: Click here to view code image
template
class MultiArray; // OK: declares a nontype template parameter pack
using TransformMatrix = MultiArray; // OK: 3x3 matrix
template… Containers>
void testContainers(); // OK: declares a template template parameter
pack

The MultiArray example requires all nontype template arguments to be of the
same type unsigned. C++17 introduced the possibility of deduced nontype
template arguments, which allows us to work around that restriction to some
extent—see Section 15.10.1 on page 298 for details.
Primary class templates, variable templates, and alias templates may have at
most one template parameter pack and, if present, the template parameter pack

must be the last template parameter. Function templates have a weaker
restriction: Multiple template parameter packs are permitted, as long as each
template parameter subsequent to a template parameter pack either has a default
value (see the next section) or can be deduced (see Chapter 15): Click here to
view code image
template
class LastType; // ERROR: template parameter pack is not the last
template parameter
template
void runTests(T value); // OK: template parameter pack is followed
// by a deducible template parameter
template struct Tensor;
template
auto compose(Tensor, Tensor);
// OK: the tensor dimensions can be deduced

The last example is the declaration of a function with a deduced return type—
a C++14 feature. See also Section 15.10.1 on page 296.
Declarations of partial specializations of class and variable templates (see
Chapter 16) can have multiple parameter packs, unlike their primary template
counterparts. That is because partial specialization are selected through a
deduction process that is nearly identical to that used for function templates.
Click here to view code image
template Typelist;
template struct Zip;
template
struct Zip, Typelist>;
// OK: partial specialization uses deduction to determine
// theXs and Ys substitutions

Perhaps not surprisingly, a type parameter pack cannot be expanded in its own
parameter clause. For example: Click here to view code image
template struct StaticValues {};
// ERROR: Ts cannot be expanded in its own parameter list

However, nested templates can create similar valid situations: Click here to view
code image
template struct ArgList {
template struct Vals {};
};
ArgList::Vals<3, ’x’, ’y’> tada; A template that
contains a template parameter pack is called a variadic template
because it accepts a variable number of template arguments. Chapter 4
and Section 12.4 on page 200 describe the use of variadic templates.

12.2.5 Default Template Arguments
Any kind of template parameter that is not a template parameter pack can be
equipped with a default argument, although it must match the corresponding
parameter in kind (e.g., a type parameter cannot have a nontype default
argument). A default argument cannot depend on its own parameter, because the
name of the parameter is not in scope until after the default argument. However,
it may depend on previous parameters: Click here to view code image
template>
class List; A template parameter for a class template, variable
template, or alias template can have a default template argument only
if default arguments were also supplied for the subsequent
parameters. (A similar constraint exists for default function call
arguments.) The subsequent default values are usually provided in the
same template declaration, but they could also have been declared in
a previous declaration of that template. The following example makes
this clear: Click here to view code image
template
class Quintuple; // OK
template
class Quintuple; // OK: T4 and T5 already have defaults
template
class Quintuple; // ERROR: T1 cannot have a default argument
// because T2 doesn’t have a default

Default template arguments for template parameters of function templates do not
require subsequent template parameters to have a default template argument:6
Click here to view code image
template
R* addressof(T& value); // OK: if not explicitly specified, R will be
void

Default template arguments cannot be repeated: Click here to view code image
template
class Value;
template
class Value; // ERROR: repeated default argument

A number of contexts do not permit default template arguments: • Partial

specializations:
Click here to view code image
template
class C;
…
template
class C; // ERROR

• Parameter packs:
Click here to view code image
template struct X; // ERROR

• The out-of-class definition of a member of a class template: Click here to view
code image
template struct X
{
T f();
};
template T X::f() { // ERROR
…
}

• A friend class template declaration:
Click here to view code image
struct S {
template friend struct F;
};

• A friend function template declaration unless it is a definition and no
declaration of it appears anywhere else in the translation unit: Click here to
view code image
struct S {
template friend void f(); // ERROR: not a definition
template friend void g() { //OK so far
}
};
template void g(); // ERROR: g() was given a default
template argument
// when defined; no other declaration may exist here

12.3 Template Arguments
When instantiating a template, template parameters are substituted by template

arguments. The arguments can be determined using several different
mechanisms: • Explicit template arguments: A template name can be followed
by explicit template arguments enclosed in angle brackets. The resulting name is
called a template-id.
• Injected class name: Within the scope of a class template X with template
parameters P1, P2, … , the name of that template (X) can be equivalent to the
template-id X. See Section 13.2.3 on page 221 for details.
• Default template arguments: Explicit template arguments can be omitted from
template instances if default template arguments are available. However, for a
class or alias template, even if all template parameters have a default value, the
(possibly empty) angle brackets must be provided.
• Argument deduction: Function template arguments that are not explicitly
specified may be deduced from the types of the function call arguments in a
call. This is described in detail in Chapter 15. Deduction is also done in a few
other situations. If all the template arguments can be deduced, no angle
brackets need to be specified after the name of the function template. C++17
also introduces the ability to deduce class template arguments from the
initializer of a variable declaration or functional-notation type conversion; see
Section 15.12 on page 313 for a discussion.

12.3.1 Function Template Arguments
Template arguments for a function template can be specified explicitly, deduced
from the way the template is used, or provided as a default template argument.
For example: Click here to view code image
details/max.cpp
template
T max (T a, T b)
{
return b < a ? a : b;
}
int main()
{
::max(1.0, -3.0); // explicitly specify template argument
::max(1.0, -3.0); // template argument is implicitly deduced to be
double
::max(1.0, 3.0); // the explicit  inhibits the deduction;
// hence the result has type int

}

Some template arguments can never be deduced because their corresponding
template parameter does not appear in a function parameter type or for some
other reason (see Section 15.2 on page 271). The corresponding parameters are
typically placed at the beginning of the list of template parameters so they can be
specified explicitly while allowing the other arguments to be deduced. For
example: Click here to view code image
details/implicit.cpp
template
DstT implicit_cast (SrcT const& x) // SrcT can be deduced, but DstT
cannot
{
return x;
}
int main()
{
double value = implicit_cast(-1);
}

If we had reversed the order of the template parameters in this example (in other
words, if we had written template), a call of implicit_cast would have to specify both template
arguments explicitly.
Moreover, such parameters can’t usefully be placed after a template parameter
pack or appear in a partial specialization, because there would be no way to
explicitly specify or deduce them.
Click here to view code image
template
void f(double (&)[N+1], Ts … ps); // useless declaration because N
// cannot be specified or deduced

Because function templates can be overloaded, explicitly providing all the
arguments for a function template may not be sufficient to identify a single
function: In some cases, it identifies a set of functions. The following example
illustrates a consequence of this observation: Click here to view code image
template
void apply (Func funcPtr, T x)
{
funcPtr(x);
}

template void single(T);
template void multi(T);
template void multi(T*);
int main()
{
apply(&single, 3); // OK
apply(&multi, 7); // ERROR: no single multi
}

In this example, the first call to apply() works because the type of the
expression &single is unambiguous. As a result, the template argument
value for the Func parameter is easily deduced. In the second call, however,
&multi could be one of two different types and therefore Func cannot
be deduced in this case.
Furthermore, it is possible that substituting template arguments in a function
template results in an attempt to construct an invalid C++ type or expression.
Consider the following overloaded function template (RT1 and RT2 are
unspecified types): Click here to view code image
template RT1 test(typename T::X const*);
template RT2 test(…); The expression test makes no
sense for the first of the two function templates because type int
has no member type X. However, the second template has no such
problem. Therefore, the expression &test identifies the address
of a single function. The fact that the substitution of int into the
first template fails does not make the expression invalid. This
SFINAE (substitution failure is not an error) principle is an
important ingredient to make the overloading of function templates
practical and is discussed in Section 8.4 on page 129 and Section
15.7 on page 284.

12.3.2 Type Arguments
Template type arguments are the “values” specified for template type
parameters. Any type (including void, function types, reference types, etc.) can,
in general, be used as a template argument, but their substitution for the template
parameters must lead to valid constructs: Click here to view code image
template
void clear (T p)
{
*p = 0; // requires that the unary * be applicable to T
}

int main()
{
int a;
clear(a); // ERROR: int doesn’t support the unary *
}

12.3.3 Nontype Arguments
Nontype template arguments are the values substituted for nontype parameters.
Such a value must be one of the following things: • Another nontype template
parameter that has the right type.
• A compile-time constant value of integer (or enumeration) type. This is
acceptable only if the corresponding parameter has a type that matches that of
the value or a type to which the value can be implicitly converted without
narrowing. For example, a char value can be provided for an int parameter,
but 500 is not valid for an 8-bit char parameter.
• The name of an external variable or function preceded by the built-in unary &
(“address of”) operator. For functions and array variables, & can be left out.
Such template arguments match nontype parameters of a pointer type. C++17
relaxed this requirement to permit any constant-expression that produces a
pointer to a function or variable.
• The previous kind of argument but without a leading & operator is a valid
argument for a nontype parameter of reference type. Here too, C++17 relaxed
the constraint to permit any constant-expression glvalue for a function or
variable.
• A pointer-to-member constant; in other words, an expression of the form
&C::m where C is a class type and m is a nonstatic member (data or function).
This matches nontype parameters of pointer-to-member type only. And again,
in C++17, the actual syntactic form is no longer constrained: Any constantexpression evaluating to a matching pointer-to-member constant is permitted.
• A null pointer constant is a valid argument for a nontype parameter of pointer
or pointer-to-member type.
For nontype parameters of integral type—probably the most common kind of
nontype parameter— implicit conversions to the parameter type are considered.
With the introduction of constexpr conversion functions in C++11, this
means that the argument before conversion can have a class type.
Prior to C++17, when matching an argument to a parameter that is a pointer or

reference, user-defined conversions (constructors for one argument and
conversion operators) and derived-to-base conversions are not considered, even
though in other circumstances they would be valid implicit conversions. Implicit
conversions that make an argument more const and/or more volatile are
fine.
Here are some valid examples of nontype template arguments: Click here to
view code image
template
class C;
C* c1; // integer type
int a;
C* c2; // address of an external variable
void f();
void f(int);
C* c3; // name of a function: overload resolution
selects
// f(int) in this case; the & is implied
template void templ_func();
C>* c4; // function template
instantiations are functions
struct X {
static bool b;
int n;
constexpr operator int() const { return 42; }
};
C* c5; // static class members are acceptable
variable/function names
C* c6; // an example of a pointer-to-member constant
C* c7; // OK: X is first converted to int via a constexpr
conversion
// function and then to long via a standard integer conversion

A general constraint of template arguments is that a compiler or a linker must be
able to express their value when the program is being built. Values that aren’t
known until a program is run (e.g., the address of local variables) aren’t
compatible with the notion that templates are instantiated when the program is
built.
Even so, there are some constant values that are, perhaps surprisingly, not
currently valid: • Floating-point numbers
• String literals (Prior to C++11, null pointer constants were not permitted

either.) One of the problems with string literals is that two identical literals can
be stored at two distinct addresses. An alternative (but cumbersome) way to
express templates instantiated over constant strings involves introducing an
additional variable to hold the string: Click here to view code image
template
class Message {
…
};
extern char const hello[] = "Hello World!";
char const hello11[] = "Hello World!";
void foo()
{
static char const hello17[] = "Hello World!";
Message msg03; // OK in all versions
Message msg11; // OK since C++11
Message msg17; // OK since C++17
}

The requirement is that a nontype template parameter declared as reference or
pointer can be a constant expression with external linkage in all C++ versions,
internal linkage since C++11, or any linkage since C++17.
See Section 17.2 on page 354 for a discussion of possible future changes in
this area Here are a few other (less surprising) invalid examples: Click here to
view code image
template
class C;
struct Base {
int i;
} base;
struct Derived : public Base {
} derived;
C* err1; // ERROR: derived-to-base conversions are
not considered
C* err2; // ERROR: fields of variables aren’t
considered to be variables
int a[10];
C* err3; // ERROR: addresses of array elements aren’t
acceptable either

12.3.4 Template Template Arguments
A template template argument must generally be a class template or alias
template with parameters that exactly match the parameters of the template
template parameter it substitutes. Prior to C++17, default template arguments of
a template template argument were ignored (but if the template template
parameter has default arguments, they are considered during the instantiation of
the template). C++17 relaxed the matching rule to just require that the template
template parameter be at least as specialized (see Section 16.2.2 on page 330) as
the corresponding template template argument.
This makes the following example invalid prior to C++17: Click here to view
code image
#include 
// declares in namespace std:
// template>
// class list;
template class Cont> // Cont expects one parameter
class Rel {
…
};
Rel rel; // ERROR before C++17: std::list has
more than
// one template parameter

The problem in this example is that the std::list template of the standard
library has more than one parameter. The second parameter (which describes an
allocator) has a default value, but prior to C++17, that is not considered when
matching std::list to the Container parameter.
Variadic template template parameters are an exception to the pre-C++17
“exact match” rule described above and offer a solution to this limitation: They
enable more general matching against template template arguments. A template
template parameter pack can match zero or more template parameters of the
same kind in the template template argument: Click here to view code image
#include 
template class Cont> // Cont expects any number of
class Rel { // type parameters
…
};

Rel rel; // OK: std::list has two template
parameters
// but can be used with one argument

Template parameter packs can only match template arguments of the same kind.
For example, the following class template can be instantiated with any class
template or alias template having only template type parameters, because the
template type parameter pack passed there as TT can match zero or more
template type parameters: Click here to view code image
#include 
#include 
// declares in namespace std:
// template,
// typename Allocator = allocator>>
// class map;
#include 
// declares in namespace std:
// template
// class array;
template class TT>
class AlmostAnyTmpl {
};
AlmostAnyTmpl withVector; //two type parameters
AlmostAnyTmpl withMap; // four type parameters
AlmostAnyTmpl withArray; // ERROR: a template type
parameter pack
// doesn’t match a nontype template parameter

The fact that, prior to C++17, only the keyword class could be used to declare
a template template parameter does not indicate that only class templates
declared with the keyword class were allowed as substituting arguments.
Indeed, struct, union, and alias templates are all valid arguments for a
template template parameter (alias templates since C++11, when they were
introduced). This is similar to the observation that any type can be used as an
argument for a template type parameter declared with the keyword class.

12.3.5 Equivalence
Two sets of template arguments are equivalent when values of the arguments are
identical one-forone. For type arguments, type aliases don’t matter: It is the type

ultimately underlying the type alias declaration that is compared. For integer
nontype arguments, the value of the argument is compared; how that value is
expressed doesn’t matter. The following example illustrates this concept: Click
here to view code image
template
class Mix;
using Int = int;
Mix* p1;
Mix* p2; // p2 has the same type as p1

(As is clear from this example, no template definition is needed to establish the
equivalence of the template argument lists.) In template-dependent contexts,
however, the “value” of a template argument cannot always be established
definitely, and the rules for equivalence become a little more complicated.
Consider the following example: Click here to view code image
template struct I {};
template void f(I); // #1
template void f(I); // #2
template void f(I); // #3 ERROR

Study declarations #1 and #2 carefully, and you’ll notice that by just renaming M
and N to, respectively, N and M, you obtain the same declaration: The two are
therefore equivalent and declare the same function template f. The expressions
M+N and N+M in those two declarations are called equivalent.
Declaration #3 is, however, subtly different: The order of the operands is
inverted. That makes the expression N+M in #3 not equivalent to either of the
other two expressions. However, because the expression will produce the same
result for any values of the template parameters involved, those expressions are
called functionally equivalent. It is an error for templates to be declared in ways
that differ only because the declarations include functionally equivalent
expressions that are not actually equivalent. However, such an error need not be
diagnosed by your compiler. That’s because some compilers may, for example,
internally represent N+1+1 in exactly the same way as N+2, whereas other
compilers may not. Rather than impose a specific implementation approach, the
standard allows either one and requires programmers to be careful in this area.
A function generated from a function template is never equivalent to an
ordinary function even though they may have the same type and the same name.
This has two important consequences for class members: 1. A function generated

from a member function template never overrides a virtual function.
2. A constructor generated from a constructor template is never a copy or move
constructor.7 Similarly, an assignment generated from an assignment template
is never a copy-assignment or move-assignment operator. (However, this is
less prone to problems because implicit calls of copy-assignment or moveassignment operators are less common.) This can be good and bad. See
Section 6.2 on page 95 and Section 6.4 on page 102 for details.

12.4 Variadic Templates
Variadic templates, introduced in Section 4.1 on page 55, are templates that
contain at least one template parameter pack (see Section 12.2.4 on page 188).8
Variadic templates are useful when a template’s behavior can be generalized to
any number of arguments. The Tuple class template introduced in Section
12.2.4 on page 188 is one such type, because a tuple can have any number of
elements, all of which are treated the same way. We can also imagine a simple
print() function that takes any number of arguments and displays each of
them in sequence.
When template arguments are determined for a variadic template, each
template parameter pack in the variadic template will match a sequence of zero
or more template arguments. We refer to this sequence of template arguments as
an argument pack. The following example illustrates how the template parameter
pack Types matches to different argument packs depending on the template
arguments provided for Tuple: Click here to view code image
template
class Tuple {
// provides operations on the list of types in Types
};
int main() {
Tuple<> t0; // Types contains an empty list
Tuple t1; // Types contains int
Tuple t2; // Types contains int and float
}

Because a template parameter pack represents a list of template arguments rather
than a single template argument, it must be used in a context where the same
language construct applies to all of the arguments in the argument pack. One
such construct is the sizeof… operation, which counts the number of
arguments in the argument pack: Click here to view code image

template
class Tuple {
public:
static constexpr std::size_t length = sizeof…(Types);
};
int a1[Tuple::length]; // array of one integer
int a3[Tuple::length]; // array of three integers

12.4.1 Pack Expansions
The sizeof… expression is an example of a pack expansion. A pack expansion
is a construct that expands an argument pack into separate arguments. While
sizeof… performs this expansion just to count the number of separate
arguments, other forms of parameter packs—those that occur where C++ expects
a list—can expand to multiple elements within that list. Such pack expansions
are identified by an ellipsis (…) to the right of an element in the list. Here is a
simple example where we create a new class template MyTuple that derives
from Tuple, passing along its arguments: Click here to view code image
template
class MyTuple : public Tuple {
// extra operations provided only for MyTuple
};
MyTuple t2; // inherits from Tuple

The template argument Types… is a pack expansion that produces a sequence of
template arguments, one for each argument within the argument pack substituted
for Types. As illustrated in the example, the instantiation of type
MyTuple substitutes the argument pack int, float for the
template type parameter pack Types. When this occurs in the pack expansion
Types…, we get one template argument for int and one for float, so
MyTuple inherits from Tuple.
An intuitive way to understand pack expansions is to think of them in terms of
a syntactic expansion, where template parameter packs are replaced with exactly
the right number of (non-pack) template parameters and pack expansions are
written out as separate arguments, once for each of the non-pack template
parameters. For example, here is how MyTuple would look if it were expanded
for two parameters:9
Click here to view code image

template
class MyTuple : public Tuple {
// extra operations provided only for MyTuple
};

and for three parameters:
Click here to view code image
template
class MyTuple : public Tuple {
// extra operations provided only for MyTuple
};

However, note that you can’t access the individual elements of a parameter pack
directly by name, because names such as T1, T2, and so on, are not defined in a
variadic template. If you need the types, the only thing you can do is to pass
them (recursively) to another class or function.
Each pack expansion has a pattern, which is the type or expression that will
be repeated for each argument in the argument pack and typically comes before
the ellipsis that denotes the pack expansion. Our prior examples have had only
trivial patterns—the name of the parameter pack—but patterns can be arbitrarily
complex. For example, we can define a new type PtrTuple that derives from a
Tuple of pointers to its argument types: Click here to view code image
template
class PtrTuple : public Tuple {
// extra operations provided only for PtrTuple
};
PtrTuple t3; // Inherits from Tuple

The pattern for the pack expansion Types*… in the example above is Types*.
Repeated substitution into this pattern produces a sequence of template type
arguments, all of which are pointers to the types in the argument pack substituted
for Types. Under the syntactic interpretation of pack expansions, here is how
PtrTuple would look if it were expanded for three parameters: Click here to
view code image
template
class PtrTuple : public Tuple {
// extra operations provided only for PtrTuple
};

12.4.2 Where Can Pack Expansions Occur?

Our examples thus far have focused on the use of pack expansions to produce a
sequence of template arguments. In fact, pack expansions can be used essentially
anywhere in the language where the grammar provides a comma-separated list,
including: • In the list of base classes.
• In the list of base class initializers in a constructor.
• In a list of call arguments (the pattern is the argument expression).
• In a list of initializers (e.g., in a braced initializer list).
• In the template parameter list of a class, function, or alias template.
• In the list of exceptions that can be thrown by a function (deprecated in C++11
and C++14, and disallowed in C++17).
• Within an attribute, if the attribute itself supports pack expansions (although no
such attribute is defined by the C++ standard).
• When specifying the alignment of a declaration.
• When specifying the capture list of a lambda.
• In the parameter list of a function type.
• In using declarations (since C++17; see Section 4.4.5 on page 65). We’ve
already mentioned sizeof… as a pack-expansion mechanism that does not
actually produce a list. C++17 also adds fold expressions, which are another
mechanism that does not produce a comma-separated list (see Section 12.4.6
on page 207.
Some of these pack-expansion contexts are included merely for the sake of
completeness, so we will focus our attention on only those pack-expansion
contexts that tend to be useful in practice. Since pack expansions in all contexts
follow the same principles and syntax, you should be able to extrapolate from
the examples given here should you find a need for the more esoteric packexpansion contexts.
A pack expansion in a list of base classes expands to some number of direct
base classes. Such expansions can be useful to aggregate externally supplied data
and functionality via mixins, which are classes intended to be “mixed into” a
class hierarchy to provide new behaviors. For example, the following Point
class uses pack expansions in several different contexts to allow arbitrary
mixins:10
Click here to view code image
template
class Point : public Mixins… { //base class pack expansion
double x, y, z;
public:
Point() : Mixins()… { } // base class initializer pack expansion

template
void visitMixins(Visitor visitor) {
visitor(static_cast(*this)…); // call argument pack
expansion
}
};
struct Color { char red, green, blue; };
struct Label { std::string name; };
Point p; // inherits from both Color and Label

The Point class uses a pack expansion to take each of the supplied mixins and
expand it into a public base class. The default constructor of Point then applies
a pack expansion in the base initializer list to value-initialize each of the base
classes introduced via the mixin mechanism.
The member function template visitMixins is the most interesting in that
it uses the results of a pack expansion as arguments to a call. By casting *this
to each of the mixin types, the pack expansion produces call arguments that refer
to each of the base classes corresponding to the mixins. Actually writing a visitor
for use with visitMixins, which can make use of such an arbitrary number
of function call arguments, is covered in Section 12.4.3 on page 204.
A pack expansion can also be used within a template parameter list to create a
nontype or template parameter pack: Click here to view code image
template
struct Values {
template
struct Holder {
};
};
int i;
Values::Holder<’a’, 17, &i> valueHolder; Note that
once the type arguments for Values<…> have been specified, the
nontype argument list for Values<…>::Holder has a fixed length; the
parameter pack Vs is thus not a variable-length parameter pack.

Values is a nontype template parameter pack for which each of the actual
template arguments can have a different type, as specified by the types provided
for the template type parameter pack Types. Note that the ellipsis in the
declaration of Values plays a dual role, both declaring the template parameter
as a template parameter pack and declaring the type of that template parameter
pack as a pack expansion. While such template parameter packs are rare in
practice, the same principle applies in a much more general context: function
parameters.

12.4.3 Function Parameter Packs
A function parameter pack is a function parameter that matches zero or more
function call arguments. Like a template parameter pack, a function parameter
pack is introduced using an ellipsis (…) prior to (or in the place of) the function
parameter name and, also like a template parameter pack, a function parameter
pack must be expanded by a pack expansion whenever it is used. Template
parameter packs and function parameter packs together are referred to as
parameter packs.
Unlike template parameter packs, function parameter packs are always pack
expansions, so their declared types must include at least one parameter pack. In
the following example, we introduce a new Point constructor that copyinitializes each of the mixins from supplied constructor arguments: Click here to
view code image
template
class Point : public Mixins…
{
double x, y, z;
public:
//default constructor, visitor function, etc. elided
Point(Mixins… mixins) // mixins is a function parameter pack
: Mixins(mixins)… { } //initialize each base with the supplied mixin
value
};
struct Color { char red, green, blue; };
struct Label { std::string name; };
Point p({0x7F, 0, 0x7F}, {"center"}); A function
parameter pack for a function template may depend on template
parameter packs declared in that template, which allows the function
template to accept an arbitrary number of call arguments without
losing type information: Click here to view code image
template
void print(Types… values);
int main
{
std::string welcome("Welcome to ");
print(welcome, "C++", 2011, ’\n’); //calls print

When calling the function template print() with some number of arguments,
the types of the arguments will be placed in the argument pack to be substituted
for the template type parameter pack Types, while the actual argument values

will be placed into an argument pack to be substituted for the function parameter
pack values. The process by which the arguments are determined from the call
is described in detail in Chapter 15. For now, it suffices to note that the ith type in
Types is the type of the ith value in Values and that both of these parameter
packs are available within the body of the function template print().
The actual implementation of print() uses recursive template instantiation,
a template metaprogramming technique described in Section 8.1 on page 123
and Chapter 23.
There is a syntactic ambiguity between an unnamed function parameter pack
appearing at the end of a parameter list and a C-style “vararg” parameter. For
example: Click here to view code image
template void c_style(int, T…);
template void pack(int, T…); In the first case, the “T…”
is treated as “T, …”: an unnamed parameter of type T followed by a Cstyle vararg parameter. In the second case, the “T…” construct is
treated as a function parameter pack because T is a valid expansion
pattern. The disambiguation can be forced by adding a comma before
the ellipsis (which ensures the ellipsis is treated as a C-style
“vararg” parameter) or by following the … by an identifier, which
makes it a named function parameter pack. Note that in generic
lambdas, a trailing … will be treated as denoting a parameter pack if
the type that immediately precedes it (with no intervening comma)
contains auto.

12.4.4 Multiple and Nested Pack Expansions
The pattern of a pack expansion can be arbitrarily complex and may include
multiple, distinct parameter packs. When instantiating a pack expansion
containing multiple parameter packs, all of the parameter packs must have the
same length. The resulting sequence of types or values will be formed elementwise by substituting the first argument of each parameter pack into the pattern,
followed by the second argument of each parameter pack, and so on. For
example, the following function copies all of its arguments before forwarding
them on to the function object f: Click here to view code image
template
void forwardCopy(F f, Types const&… values) {
f(Types(values)…);
}

The call argument pack expansion names two parameters packs, Types and
values. When instantiating this template, the element-wise expansion of the

Types and values parameter packs produces a series of object constructions,
which builds a copy of the ith value in values by casting it to the ith type in
Types. Under the syntactic interpretation of pack expansions, a three-argument
forwardCopy would look like this: Click here to view code image
template
void forwardCopy(F f, T1 const& v1, T2 const& v2, T3 const& v3) {
f(T1(v1), T2(v2), T3(v3));
}

Pack expansions themselves may also be nested. In such cases, each occurrence
of a parameter pack is “expanded” by its nearest enclosing pack expansion (and
only that pack expansion). The following examples illustrates a nested pack
expansion involving three different parameter packs: Click here to view code
image
template
class Nested {
template
void f(InnerTypes const&… innerValues) {
g(OuterTypes(InnerTypes(innerValues)…)…);
}
};

In the call to g(), the pack expansion with pattern
InnerTypes(innerValues) is the innermost pack expansion, which
expands both InnerTypes and innerValues and produces a sequence of
function call arguments for the initialization of an object denoted by
OuterTypes. The outer pack expansion’s pattern includes the inner pack
expansion, producing a set of call arguments for the function g(), created from
the initialization of each of the types in OuterTypes from the sequence of
function call arguments produced by the inner expansion. Under the syntactic
interpretation of this pack expansion, where OuterTypes has two arguments
and both InnerTypes and innerValues have three arguments, the nesting
becomes more apparent: Click here to view code image
template
class Nested {
template
void f(I1 const& iv1, I2 const& iv2, I3 const& iv3) {
g(O1(I1(iv1), I2(iv2), I3(iv3)),
O2(I1(iv1), I2(iv2), I3(iv3)),
O3(I1(iv1), I2(iv2), I3(iv3)));
}
};

Multiple and nested pack expansions are a powerful tool (e.g., see Section 26.2

on page 608).

12.4.5 Zero-Length Pack Expansions
The syntactic interpretation of pack expansions can be a useful tool for
understanding how an instantiation of a variadic template will behave with
different numbers of arguments. However, the syntactic interpretation often fails
in the presence of zero-length argument packs. To illustrate this, consider the
Point class template from Section 12.4.2 on page 202, syntactically substituted
with zero arguments: template<>
class Point : {
Point() : { }
};
The code as written above is ill-formed, since the template parameter list is now
empty and the empty base class and base class initializer lists each have a stray
colon character.
Pack expansions are actually semantic constructs, and the substitution of an
argument pack of any size does not affect how the pack expansion (or its
enclosing variadic template) is parsed. Rather, when a pack expansion expands
to an empty list, the program behaves (semantically) as if the list were not
present. The instantiation Point<> ends up having no base classes, and its
default constructor has no base class initializers but is otherwise well-formed.
This semantic rules holds even when the syntactic interpretation of zero-length
pack expansion would be well-defined (but different) code. For example: Click
here to view code image
template
void g(Types… values) {
T v(values…);
}

The variadic function template g() creates a value v that is direct-initialized
from the sequence of values it is given. If that sequence of values is empty, the
declaration of v looks, syntactically, like a function declaration T v().
However, since substitution into a pack expansion is semantic and cannot affect
the kind of entity produced by parsing, v is initialized with zero arguments, that
is, value-initialization.11

12.4.6 Fold Expressions
A recurring pattern in programming is the fold of an operation on a sequence of
values. For example, a right fold of a function fn over a sequence x[1],
x[2], …, x[n-1], x[n] is given by fn(x[1], fn(x[2], fn(…,
fn(x[n-1], x[n])…))) While exploring a new language feature, the C++
committee ran into the need to deal with such constructs for the special case of a
logical binary operator (i.e., && or ||) applied to a pack expansion. Without an
extra feature, we might write the following code to achieve that for the &&
operator: Click here to view code image
bool and_all() { return true; }
template
bool and_all(T cond) { return cond; }
template
bool and_all(T cond, Ts… conds) {
return cond && and_all(conds…);
}

With C++17, a new feature called fold expressions was added (see Section 4.2
on page 58 for an introduction). It applies to all binary operators except ., ->,
and [].
Given an unexpanded expression pattern pack and a nonpattern expression
value, C++17 allows us to write for any such operator op, either (pack op … op
value) for a right fold of the operator (called a binary right fold), or (value op …
op pack) for a left fold (called a binary left fold). Note that the parentheses are
required here. See Section 4.2 on page 58 for some basic examples.
The fold operation applies to the sequence that results from expanding the
pack and adding value as either the last element of the sequence (for a right
fold) or the first element of the sequence (for a left fold).
With this feature available, code like
Click here to view code image
template bool g() {
return and_all(trait()…);
}

(where and_all is as defined above), can instead be written as Click here to
view code image
template bool g() {
return (trait() && … && true);
}

As you’d expect, fold expressions are pack expansions. Note that if the pack is
empty, the type of the fold expression can still be determined from the non-pack
operand (value in the forms above).
However, the designers of this feature also wanted an option to leave out the
value operand. Two other forms are therefore available in C++17: The unary
right fold
(pack op … ) and the unary left fold
(… op pack) Again, the parentheses are required. Clearly this creates
a problem for empty expansions: How do we determine their type and
value? The answer is that an empty expansion of a unary fold is
generally an error, with three exceptions: • An empty expansion of a
unary fold of && produces the value true,.

• An empty expansion of a unary fold of || produces the value false.
• An empty expansion of a unary fold of the comma operator (,) produces a
void expression.
Note that this will create surprises if you overload one of these special operators
in a somewhat unusual way. For example: Click here to view code image
struct BooleanSymbol {
…
};
BooleanSymbol operator||(BooleanSymbol, BooleanSymbol);
template void symbolic(BTs… ps) {
BooleanSymbol result = (ps || …);
…
}

Suppose we call symbolic with types that are derived from
BooleanSymbol. For all expansions, the result will produce a
BooleanSymbol value except for the empty expansion, which will produce a
bool value.12 We therefore generally caution against the use of unary fold
expressions, and recommend using binary fold expressions instead (with an
explicitly specified empty expansion value).

12.5 Friends
The basic idea of friend declarations is a simple one: Identify classes or
functions that have a privileged connection with the class in which the friend
declaration appears. Matters are somewhat complicated, however, by two facts:

1. A friend declaration may be the only declaration of an entity.
2. A friend function declaration can be a definition.

12.5.1 Friend Classes of Class Templates
Friend class declarations cannot be definitions and therefore are rarely
problematic. In the context of templates, the only new facet of friend class
declarations is the ability to name a particular instance of a class template as a
friend: template
class Node;
template
class Tree {
friend class Node;
…
};
Note that the class template must be visible at the point where one of its
instances is made a friend of a class or class template. With an ordinary class,
there is no such requirement: Click here to view code image
template
class Tree {
friend class Factory; // OK even if first declaration of Factory
friend class Node; // error if Node isn’t visible
};

Section 13.2.2 on page 220 has more to say about this.
One application, introduced in Section 5.5 on page 75, is the declaration of
other class template instantiations to be friends: Click here to view code image
template
class Stack {
public:
…
// assign stack of elements of type T2
template
Stack& operator= (Stack const&);
// to get access to private members of Stack for any type T2:
template friend class Stack;
…
};

C++11 also added syntax to make a template parameter a friend:
template

class Wrap {
friend T;
…
};
This is valid for any type T but is ignored if T is not actually a class type.13

12.5.2 Friend Functions of Class Templates
An instance of a function template can be made a friend by making sure the
name of the friend function is followed by angle brackets. The angle brackets
can contain the template arguments, but if the arguments can be deduced, the
angle brackets can be left empty: Click here to view code image
template
void combine(T1, T2);
class Mixer {
friend void combine<>(int&, int&);
// OK: T1 = int&, T2 = int&
friend void combine(int, int);
// OK: T1 = int, T2 = int
friend void combine(char, int);
// OK: T1 = char T2 = int
friend void combine(char&, int);
// ERROR: doesn’t match combine() template
friend void combine<>(long, long) { … }
// ERROR: definition not allowed!
};

Note that we cannot define a template instance (at most, we can define a
specialization), and hence a friend declaration that names an instance cannot be a
definition.
If the name is not followed by angle brackets, there are two possibilities: 1. If
the name isn’t qualified (in other words, it doesn’t contain ::), it never refers to
a template instance. If no matching nontemplate function is visible at the point of
the friend declaration, the friend declaration is the first declaration of that
function. The declaration could also be a definition.
2. If the name is qualified (it contains ::), the name must refer to a previously
declared function or function template. A matching function is preferred over
a matching function template. However, such a friend declaration cannot be a
definition. An example may help clarify the various possibilities: Click here to
view code image

void multiply(void*); // ordinary function
template
void multiply(T); // function template
class Comrades {
friend void multiply(int) { }
// defines a new function ::multiply(int)
friend void ::multiply(void*);
// refers to the ordinary function above,
// not to the multiply instance
friend void ::multiply(int);
// refers to an instance of the template
friend void ::multiply(double*);
// qualified names can also have angle brackets,
// but a template must be visible
friend void ::error() { }
// ERROR: a qualified friend cannot be a definition
};

In our previous examples, we declared the friend functions in an ordinary class.
The same rules apply when we declare them in class templates, but the template
parameters may participate in identifying the function that is to be a friend: Click
here to view code image
template
class Node {
Node* allocate();
…
};
template
class List {
friend Node* Node::allocate();
…
};

A friend function may also be defined within a class template, in which case it is
only instantiated when it is actually used. This typically requires the friend
function to use the class template itself in the type of the friend function, which
makes it easier to express functions on the class template that can be called as if
they were visible in namespace scope: Click here to view code image
template
class Creator {
friend void feed(Creator) { //every T instantiates a different
function ::feed()
…
}

};
int main()
{
Creator one;
feed(one); // instantiates ::feed(Creator)
Creator two;
feed(two); // instantiates ::feed(Creator)
}

In this example, every instantiation of Creator generates a different function.
Note that even though these functions are generated as part of the instantiation of
a template, the functions themselves are ordinary functions, not instances of a
template. However, they are considered templated entities (see Section 12.1 on
page 181) and their definition is instantiated only when used. Also note that
because the body of these functions is defined inside a class definition, they are
implicitly inline. Hence, it is not an error for the same function to be generated
in two different translation units. Section 13.2.2 on page 220 and Section 21.2.1
on page 497 have more to say about this topic.

12.5.3 Friend Templates
Usually when declaring a friend that is an instance of a function or a class
template, we can express exactly which entity is to be the friend. Sometimes it is
nonetheless useful to express that all instances of a template are friends of a
class. This requires a friend template. For example: Click here to view code
image
class Manager {
template
friend class Task;
template
friend void Schedule::dispatch(Task*);
template
friend int ticket() {
return ++Manager::counter;
}
static int counter;
};

Just as with ordinary friend declarations, a friend template can be a definition
only if it names an unqualified function name that is not followed by angle
brackets.

A friend template can declare only primary templates and members of primary
templates. Any partial specializations and explicit specializations associated with
a primary template are automatically considered friends too.

12.6 Afternotes
The general concept and syntax of C++ templates have remained relatively
stable since their inception in the late 1980s. Class templates and function
templates were part of the initial template facility. So were type parameters and
nontype parameters.
However, there were also some significant additions to the original design,
mostly driven by the needs of the C++ standard library. Member templates may
well be the most fundamental of those additions. Curiously, only member
function templates were formally voted into the C++ standard. Member class
templates became part of the standard by an editorial oversight.
Friend templates, default template arguments, and template template
parameters came afterward during the standardization of C++98. The ability to
declare template template parameters is sometimes called higher-order
genericity. They were originally introduced to support a certain allocator model
in the C++ standard library, but that allocator model was later replaced by one
that does not rely on template template parameters. Later, template template
parameters came close to being removed from the language because their
specification had remained incomplete until very late in the standardization
process for the 1998 standard. Eventually a majority of committee members
voted to keep them and their specifications were completed.
Alias templates were introduced as part of the 2011 standard. Alias templates
serve the same needs as the oft-requested “typedef templates” feature by making
it easy to write a template that is merely a different spelling of an existing class
template. The specification (N2258) that made it into the standard was authored
by Gabriel Dos Reis and Bjarne Stroustrup; Mat Marcus also contributed to
some of the early drafts of that proposal. Gaby also worked out the details of the
variable template proposal for C++14 (N3651). Originally, the proposal only
intended to support constexpr variables, but that restriction was lifted by the
time it was adopted in the draft standard.
Variadic templates were driven by the needs of the C++11 standard library and
the Boost libraries (see [Boost]), where C++ template libraries were using
increasingly advanced (and convoluted) techniques to provide templates that

accept an arbitrary number of template arguments. Doug Gregor, Jaakko J¨arvi,
Gary Powell, Jens Maurer, and Jason Merrill provided the initial specification
for the standard (N2242). Doug also developed the original implementation of
the feature (in GNU’s GCC) while the specification was being developed, which
much helped the ability to use the feature in the standard library.
Fold expressions were the work of Andrew Sutton and Richard Smith: They
were added to C++17 through their paper N4191.
1 An exception since C++14 are the implicit template type parameters for a
generic lambda; see Section 15.10.6 on page 309.
2 The keyword class does not imply that the substituting argument should be
a class type. It could be any accessible type.
3 Template template parameters do not denote types either; however, they are
distinct from nontype parameters. This oddity is historical: Template template
parameters were added to the language after type parameters and nontype
parameters.
4 At the time of this writing, only “pointer to object” and “pointer to function”
types are permitted, which excludes types like void*. However, all
compilers appear to accept void* also.
5 See Appendix B for a discussion of value categories such as rvalues and
lvalues.
6 Template arguments for subsequent template parameters can still be
determined by template argument deduction; see Chapter 15.
7 However, a constructor template can be a default constructor.
8 The term variadic is borrowed from C’s variadic functions, which accept a
variable number of function arguments. Variadic templates also borrowed
from C the use of the ellipsis to denote zero or more arguments and are
intended as a type-safe replacement for C’s variadic functions for some
applications.
9 This syntactic understanding of pack expansions is a useful tool, but it breaks
down when the template parameter packs have length zero. Section 12.4.5 on
page 207 provides more details about the interpretation of zero-length pack
expansions.
10 Mixins are discussed in further detail in Section 21.3 on page 508.
11 There is a similar restriction on members of class templates and nested classes
within class templates: If a member is declared with a type that does not
appear to be a function type, but after instantiation the type of that member is a
function type, the program is ill-formed because the semantic interpretation of

the member has changed from a data member to a member function.
Because overloading these three special operators is unusual, this problem is
fortunately rare (but subtle). The original proposal for fold expressions
included empty expansion values for more common operators like + and *,
which would have caused more serious problems.
13 This was the very first extension added to C++11, thanks to a proposal by
William M. “Mike” Miller.
12

Chapter 13
Names in Templates
Names are a fundamental concept in most programming languages. They are the
means by which a programmer can refer to previously constructed entities.
When a C++ compiler encounters a name, it must “look it up” to identify the
entity being referred. From an implementer’s point of view, C++ is a hard
language in this respect. Consider the C++ statement x*y;. If x and y are the
names of variables, this statement is a multiplication, but if x is the name of a
type, then the statement declares y as a pointer to an entity of type x.
This small example demonstrates that C++ (like C) is a context-sensitive
language: A construct cannot always be understood without knowing its wider
context. How does this relate to templates? Well, templates are constructs that
must deal with multiple wider contexts: (1) the context in which the template
appears, (2) the context in which the template is instantiated, and (3) the contexts
associated with the template arguments for which the template is instantiated.
Hence it should not be totally surprising that “names” must be dealt with quite
carefully in C++.

13.1 Name Taxonomy
C++ classifies names in a variety of ways—a large variety of ways, in fact. To
help cope with this abundance of terminology, we provide Table 13.1 and Table
13.2, which describe these classifications. Fortunately, you can gain good insight
into most C++ template issues by familiarizing yourself with two major naming
concepts: 1. A name is a qualified name if the scope to which it belongs is
explicitly denoted using a scope-resolution operator (::) or a member access
operator (. or ->). For example, this->count is a qualified name, but
count is not (even though the plain count might actually refer to a class
member).
2. A name is a dependent name if it depends in some way on a template
parameter. For example, std::vector::iterator is usually a

dependent name if T is a template parameter, but it is a nondependent name if
T is a known type alias (such as the T from using T = int).
Classification Explanation and Notes
Identifier

A name that consists solely of an uninterrupted sequences of
letters, underscores (_), and digits. It cannot start with a digit,
and some identifiers are reserved for the implementation: You
should not introduce them in your programs (as a rule of thumb,
avoid leading underscores and double underscores). The concept
of “letter” should be taken broadly and includes special
universal character names (UCNs) that encode glyphs from
nonalphabetical languages.

Operatorfunction-id

The keyword operator followed by the symbol for an
operator—for example, operator new and operator [
].1

Conversionfunction-id

Used to denote a user-defined implicit conversion operator—for
example, operator int&, which could also be obfuscated as
operator int bitand.

Literaloperator-id

Used to denote a user-defined literal operator—for example,
operator ""_km, which will be used when writing a literal
such as 100_km (introduced in C++11).

Template-id

The name of a template followed by template arguments
enclosed in angle brackets; for example, List.
A template-id may also be an operator-function-id or a literaloperator-id followed by template arguments enclosed in angle
brackets; for example, operator+>.

Unqualifiedid

The generalization of an identifier. It can be any of the above
(identifier, operator-function-id, conversion-function-id, literaloperator-id, or template-id) or a “destructor name” (e.g.,
notations like ~Data or ~List).

Qualified-id

An unqualified-id that is qualified with the name of a class,
enum, or namespace, or just with the global scope resolution
operator. Note that such a name itself can be qualified. Examples
are ::X, S::x, Array::y, and ::N::A::z.

Qualified
name

This term is not defined in the standard, but we use it to refer to
names that undergo qualified lookup. Specifically, this is a
qualifiedid or an unqualified-id that is used after an explicit
member access operator (. or ->). Examples are S::x, this>f, and p->A::m. However, just class_mem in a context that
is implicitly equivalent to this->class_mem is not a
qualified name: The member access must be explicit.

Unqualified
name

An unqualified-id that is not a qualified name. This is not a
standard term but corresponds to names that undergo what the
standard calls unqualified lookup.

Name

Either a qualified or an unqualified name.
Table 13.1. Name Taxonomy (Part 1)

Classification Explanation and Notes
Dependent
name

A name that depends in some way on a template parameter.
Typically, a qualified or unqualified name that explicitly
contains a template parameter is dependent. Furthermore, a
qualified name that is qualified by a member access operator (.
or ->) is typically dependent if the type of the expression on the
left of the access operator is type-dependent, a concept that is
discussed in Section 13.3.6 on page 233. In particular, b in
this->b is generally a dependent name when it appears in a
template. Finally, a name that is subject to argument-dependent
lookup (described in Section 13.2 on page 217), such as ident
in a call of the form ident(x, y) or + in the expression x +
y, is a dependent name if and only if any of the argument
expressions is type-dependent.

Nondependent A name that is not a dependent name by the above description.
name
Table 13.2. Name Taxonomy (Part 2)
It is useful to read through the tables to gain some familiarity with the terms that

are sometimes used to describe C++ template issues, but it is not essential to
remember the exact meaning of every term. Should the need arise, they can be
found easily in the index.

13.2 Looking Up Names
There are many small details to looking up names in C++, but we will focus only
on a few major concepts. The details are necessary to ensure only that (1) normal
cases are treated intuitively, and (2) pathological cases are covered in some way
by the standard.
Qualified names are looked up in the scope implied by the qualifying
construct. If that scope is a class, then base classes may also be searched.
However, enclosing scopes are not considered when looking up qualified names.
The following illustrates this basic principle: Click here to view code image
int x;
class B {
public:
int i;
};
class D : public B {
};
void f(D* pd)
{
pd->i = 3; // finds B::i
D::x = 2; // ERROR: does not find ::x in the enclosing scope
}

In contrast, unqualified names are typically looked up in successively more
enclosing scopes (al-though in member function definitions, the scope of the
class and its base classes is searched before any other enclosing scopes). This is
called ordinary lookup. Here is a basic example showing the main idea
underlying ordinary lookup: Click here to view code image
extern int count; // #1
int lookup_example(int count) // #2
{
if (count < 0) {
int count = 1; // #3
lookup_example(count); // unqualified count refers to #3
}

return count + ::count; // the first (unqualified) count refers to
#2;
} //the second (qualified) count refers to #1

A more recent twist to the lookup of unqualified names is that—in addition to
ordinary lookup—they may sometimes undergo argument-dependent lookup
(ADL).2 Before proceeding with the details of ADL, let’s motivate the
mechanism with our perennial max() template: template
T max (T a, T b)
{
return b < a ? a : b;
}
Suppose now that we need to apply this template to a type defined in another
namespace: Click here to view code image
namespace BigMath {
class BigNumber {
…
};
bool operator < (BigNumber const&, BigNumber const&);
…
}
using BigMath::BigNumber;
void g (BigNumber const& a, BigNumber const& b)
{
…
BigNumber x = ::max(a,b);
…
}

The problem here is that the max() template is unaware of the BigMath
namespace, but ordinary lookup would not find the operator < applicable to
values of type BigNumber. Without some special rules, this greatly reduces the
applicability of templates in the presence of C++ namespaces. ADL is the C++
answer to those “special rules.”

13.2.1 Argument-Dependent Lookup
ADL applies primarily to unqualified names that look like they name a
nonmember function in a function call or operator invocation. ADL does not
happen if ordinary lookup finds • the name of a member function,
• the name of a variable,

• the name of a type, or
• the name of a block-scope function declaration.
ADL is also inhibited if the name of the function to be called is enclosed in
parentheses.
Otherwise, if the name is followed by a list of argument expressions enclosed
in parentheses, ADL proceeds by looking up the name in namespaces and classes
“associated with” the types of the call arguments. The precise definition of these
associated namespaces and associated classes is given later, but intuitively they
can be thought of as being all the namespaces and classes that are fairly directly
connected to a given type. For example, if the type is a pointer to a class X, then
the associated classes and namespace would include X as well as any
namespaces or classes to which X belongs.
The precise definition of the set of associated namespaces and associated
classes for a given type is determined by the following rules: • For built-in types,
this is the empty set.
• For pointer and array types, the set of associated namespaces and classes is that
of the underlying type.
• For enumeration types, the associated namespace is the namespace in which
the enumeration is declared.
• For class members, the enclosing class is the associated class.
• For class types (including union types), the set of associated classes is the type
itself, the enclosing class, and any direct and indirect base classes. The set of
associated namespaces is the namespaces in which the associated classes are
declared. If the class is a class template instance, then the types of the template
type arguments and the classes and namespaces in which the template template
arguments are declared are also included.
• For function types, the sets of associated namespaces and classes comprise the
namespaces and classes associated with all the parameter types and those
associated with the return type.
• For pointer-to-member-of-class-X types, the sets of associated namespaces and
classes include those associated with X in addition to those associated with the
type of the member. (If it is a pointer-to-member-function type, then the
parameter and return types can contribute too.) ADL then looks up the name in
all the associated namespaces as if the name had been qualified with each of
these namespaces in turn, except that using directives are ignored. The
following example illustrates this: Click here to view code image
details/adl.cpp

#include 
namespace X {
template void f(T);
}
namespace N {
using namespace X;
enum E { e1 };
void f(E) {
std::cout << "N::f(N::E) called\n";
}
}
void f(int)
{
std::cout << "::f(int) called\n";
}
int main()
{
::f(N::e1); // qualified function name: no ADL
f(N::e1); // ordinary lookup finds ::f() and ADL finds N::f(),
} //the latter is preferred

Note that in this example, the using directive in namespace N is ignored when
ADL is performed. Hence X::f() is never even a candidate for the call in
main().

13.2.2 Argument-Dependent Lookup of Friend
Declarations
A friend function declaration can be the first declaration of the nominated
function. If this is the case, then the function is assumed to be declared in the
nearest namespace scope (which may be the global scope) enclosing the class
containing the friend declaration. However, such a friend declaration is not
directly visible in that scope. Consider the following example: Click here to
view code image
template
class C {
…
friend void f();
friend void f(C const&);
…

};
void g (C* p)
}
{ f(); // is f() visible here?
f(*p); // is f(C const&) visible here?
}

If friend declarations were visible in the enclosing namespace, then instantiating
a class template may make visible the declaration of ordinary functions. This
would lead to surprising behavior: The call f() would result in a compilation
error unless an instantiation of the class C occurred earlier in the program!
On the other hand, it can be useful to declare (and define) a function in a
friend declaration only (see Section 21.2.1 on page 497 for a technique that
relies on this behavior). Such a function can be found when the class of which
they are a friend is among the associated classes considered by ADL.
Reconsider our last example. The call f() has no associated classes or
namespaces because there are no arguments: It is an invalid call in our example.
However, the call f(*p) does have the associated class C (because this
is the type of *p), and the global namespace is also associated (because this is
the namespace in which the type of *p is declared). Therefore, the second friend
function declaration could be found provided the class C was actually
fully instantiated prior to the call. To ensure this, it is assumed that a call
involving a lookup for friends in associated classes actually causes the class to
be instantiated (if not done already).3
The ability of argument-dependent lookup to find friend declarations and
definition is sometimes referred to as friend name injection. However, this term
is somewhat misleading, because it is the name of a pre-standard C++ feature
that did in fact “inject” the names of friend declarations into the enclosing scope,
making them visible to normal name lookup. In our example above, this would
mean that both calls would be well-formed. This chapter’s afternotes further
detail the history of friend name injection.

13.2.3 Injected Class Names
The name of a class is injected inside the scope of that class itself and is
therefore accessible as an unqualified name in that scope. (However, it is not
accessible as a qualified name because this is the notation used to denote the
constructors.) For example: Click here to view code image

details/inject.cpp
#include 
int C;
class C {
private:
int i[2];
public:
static int f() {
return sizeof(C);
}
};
int f()
{
return sizeof(C);
}
int main()
{
std::cout << "C::f() = " << C::f() << ’,’
<< " ::f() = " << ::f() << ’\n’;
}

The member function C::f() returns the size of type C, whereas the function
::f() returns the size of the variable C (in other words, the size of an int
object).
Class templates also have injected class names. However, they’re stranger
than ordinary injected class names: They can be followed by template arguments
(in which case they are injected class template names), but if they are not
followed by template arguments they represent the class with its parameters as
its arguments (or, for a partial specialization, its specialization arguments) if the
context expects a type, or a template if the context expects a template. This
explains the following situation: Click here to view code image
template class TT> class X {
};
template class C {
C* a; // OK: same as “C* a;”
C& b; // OK
X c; // OK: C without a template argument list denotes the
template C
X<::C> d; // OK: ::C is not the injected class name and therefore
always
// denotes the template
};

Note how the unqualified name refers to the injected name and is not considered
the name of the template if it is not followed by a list of template arguments. To
compensate, we can force the name of the template to be found by using the file
scope qualifier ::.
The injected class name for a variadic template has an additional wrinkle: If
the injected class name were directly formed by using the variadic template’s
template parameters as the template arguments, the injected class name would
contain template parameter packs that have not been expanded (see Section
12.4.1 on page 201 for details of pack expansion). Therefore, when forming the
injected class name for a variadic template, the template argument that
corresponds to a template parameter pack is a pack expansion whose pattern is
that template parameter pack: Click here to view code image
template class V {
V* a; // OK: same as “V* a;”
V<0, void> b; // OK
};

13.2.4 Current Instantiations
The injected class name of a class or class template is effectively an alias for the
type being defined. For a nontemplate class, this property is obvious, because the
class itself is the only type with that name and in that scope. However, inside a
class template or a nested class within a class template, each template
instantiation produces a different type. This property is particularly interesting in
that context, because it means that the injected class name refers to the same
instantiation of the class template rather than some other specialization of that
class template (the same holds for nested classes of class templates).
Within a class template, the injected class name or any type that is equivalent
to the injected class name (including looking through type alias declarations) of
any enclosing class or class template is said to refer to a current instantiation.
Types that depend on a template parameter (i.e., dependent types) but do not
refer to a current instantiation are said to refer to an unknown specialization,
which may be instantiated from the same class template or some entirely
different class template. The following example illustrates the difference: Click
here to view code image
template class Node {
using Type = T;
Node* next; // Node refers to a current instantiation

Node* previous; // Node refers to a current instantiation
Node* parent; // Node refers to an unknown specialization
};

Identifying whether a type refers to a current instantiation can be confusing in
the presence of nested classes and class templates. The injected class names of
enclosing classes and class templates (or types equivalent to them) do refer to a
current instantiation, while the names of other nested classes or class templates
do not: Click here to view code image
template class C {
using Type = T;
struct I {
C* c; // C refers to a current instantiation
C* c2; // C refers to a current instantiation
I* i; // I refers to a current instantiation
};
struct J {
C* c; //C refers to a current instantiation
C* c2; // C refers to a current instantiation
I* i; // I refers to an unknown specialization,
// because I does not enclose
JJ* j; // J refers to a current instantiation
};
};

When a type refers to a current instantiation, the contents of that instantiated
class are guaranteed to be instantiated from the class template or nested class
thereof that is currently being defined. This has implications for name lookup
when parsing templates—the subject of our next section—but it also leads to an
alternative, more game-like way to determine whether a type X within the
definition of a class template refers to a current instantiation or an unknown
specialization: If another programmer can write an explicit specialization
(described in detail in Chapter 16) such that X refers to that specialization, then X
refers to an unknown specialization. For example, consider the instantiation of
the type C::J in the context of the above example: We know the
definition of C::J used to instantiate the concrete type (since that’s the type
we’re instantiating). Moreover, because an explicit specialization cannot
specialize a template or member of a template without also specializing all of the
enclosing templates or members, C will be instantiated from the
enclosing class definition. Hence, the references to J and C (where Type
is int) within J refer to a current instantiation. On the other hand, one could
write an explicit specialization for C::I as follows: Click here to view
code image

template<> struct C::I {
// definition of the specialization
};

Here, the specialization of C::I provides a completely different
definition than the one that was visible from the definition of C::J, so the
I inside the definition of C::J refers to an unknown specialization.

13.3 Parsing Templates
Two fundamental activities of compilers for most programming languages are
tokenization—also called scanning or lexing—and parsing. The tokenization
process reads the source code as a sequence of characters and generates a
sequence of tokens from it. For example, on seeing the sequence of characters
int* p = 0;, the “tokenizer” will generate token descriptions for a keyword
int, a symbol/operator *, an identifier p, a symbol/operator =, an integer literal
0, and a symbol/operator ;.
A parser will then find known patterns in the token sequence by recursively
reducing tokens or previously found patterns into higher level constructs. For
example, the token 0 is a valid expression, the combination * followed by an
identifier p is a valid declarator, and that declarator followed by “=” followed
by the expression “0” is a valid init-declarator. Finally, the keyword int is a
known type name, and, when followed by the init-declarator *p = 0, you get
the initializing declaration of p.

13.3.1 Context Sensitivity in Nontemplates
As you may know or expect, tokenizing is easier than parsing. Fortunately,
parsing is a subject for which a solid theory has been developed, and many
useful languages are not hard to parse using this theory. However, the theory
works best for context-free languages, and we have already noted that C++ is
context sensitive. To handle this, a C++ compiler will couple a symbol table to
the tokenizer and parser: When a declaration is parsed, it is entered in the
symbol table. When the tokenizer finds an identifier, it looks it up and annotates
the resulting token if it finds a type.
For example, if the C++ compiler sees
x*

the tokenizer looks up x. If it finds a type, the parser sees identifier,
type, x
symbol, *
and concludes that a declaration has started. However, if x is not found to be a
type, then the parser receives from the tokenizer identifier, nontype,
x
symbol, *
and the construct can be parsed validly only as a multiplication. The details of
these principles are dependent on the particular implementation strategy, but the
gist should be there.
Another example of context sensitivity is illustrated in the following
expression: X<1>(0)
If X is the name of a class template, then the previous expression casts the
integer 0 to the type X<1> generated from that template. If X is not a template,
then the previous expression is equivalent to (X<1)>0
In other words, X is compared with 1, and the result of that comparison—true or
false, implicitly converted to 1 or 0 in this case—is compared with 0. Although
code like this is rarely used, it is valid C++ (and valid C, for that matter). A C++
parser will therefore look up names appearing before a < and treat the < as an
angle bracket only if the name is known to be that of a template; otherwise, the <
is treated as an ordinary less-than operator.
This form of context sensitivity is an unfortunate consequence of having
chosen angle brackets to delimit template argument lists. Here is another such
consequence: Click here to view code image
template
class Invert {
public:
static bool const result = !B;
};
void g()
{
bool test = Invert<(1>0)>::result; // parentheses required!
}

If the parentheses in Invert<(1>0)> were omitted, the greater-than symbol
would be mistaken for the closing of the template argument list. This would
make the code invalid because the compiler would read it to be equivalent to
((Invert<1>))0>::result.4
The tokenizer isn’t spared problems with the angle-bracket notation either. For

example, in Click here to view code image
List> a;
// ^-- no space between right angle brackets

the two > characters combine into a right-shift token >> and hence are never
treated as two separate tokens by the tokenizer. This is a consequence of the
maximum munch tokenization principle: A C++ implementation must collect as
many consecutive characters as possible into a token.5
As mentioned in Section 2.2 on page 28, since C++11, the C++ standard
specifically calls out this case—where a nested template-id is closed by a rightshift token >>—and, within the parser, treats the right shift as being equivalent
to two separate right angle brackets > and > to close two template-ids at once.6
It’s interesting to note that this change silently changes the meaning of some—
admittedly contrived—programs. Consider the following example: Click here to
view code image
names/anglebrackethack.cpp
#include 
template struct X {
static int const c = 2;
};
template<> struct X<0> {
typedef int c;
};
template struct Y {
static int const c = 3;
};
static int const c = 4;
int main()
{
std::cout << (Y >::c >::c>::c) << ’ ’;
std::cout << (Y>::c >::c>::c) << ’\n’;
}

This is a valid C++98 program that outputs 0 3. It is also a valid C++11
program, but there the angle bracket hack makes the two parenthesized
expressions equivalent, and the output is 0 0.7
A similar problem existed because of the existence of the digraph <: as an
alternative for the source character [ (which is not available on some traditional

keyboards). Consider the following example: Click here to view code image
template struct G {};
struct S;
G<::S> gs; // valid since C++11, but an error before that

Before C++11, that last line of code was equivalent to G[:S> gs;, which is
clearly invalid. Another “lexical hack” was added to address that problem: When
a compiler sees the characters <:: not immediately followed by : or >, the
leading pair of characters <: is not treated as a digraph token equivalent to [.8
This digraph hack can make previously valid (but somewhat contrived)
programs invalid:9
Click here to view code image
#define F(X) X ## :
int a[] = { 1, 2, 3 }, i = 1;
int n = a F(<::)i]; // valid in C++98/C++03, but not in C++11

To understand this, note that the “digraph hack” applies to preprocessing tokens,
which are the kinds of tokens acceptable to the preprocessor (they may not be
acceptable after preprocessing has completed), and they are decided before
macro expansion completes. With that in mind, C++98/C++03 unconditionally
transforms <: into [ in the macro invocation F(<::), and the definition of n
expands to int n = a [ :: i]; which is perfectly fine. C++11, however, does not
perform the digraph transformation because, before macro expansion, the
sequence <:: is not followed by : or >, but by ). Without the digraph
transformation, the concatenation operator ## must attempt to glue :: and :
into a new preprocessing token, but that doesn’t work because ::: is not a valid
concatenation token. That standard makes this undefined behavior, which allows
the compiler to do anything. Some compilers will diagnose this problem, while
others won’t and will just keep the two preprocessing tokens separate, which is a
syntax error because it leads to a definition of n that expands to int n = a < :: : i];

13.3.2 Dependent Names of Types
The problem with names in templates is that they cannot always be sufficiently
classified. In particular, one template cannot look into another template because
the contents of that other template can be made invalid by an explicit
specialization. The following contrived example illustrates this: Click here to
view code image

template
class Trap {
public:
enum { x }; // #1 x is not a type here
};
template
class Victim {
public:
int y;
void poof() {
Trap::x * y; // #2 declaration or multiplication?
}
};
template<>
class Trap { //evil specialization!
public:
using x = int; // #3 x is a type here
};
void boom(Victim& bomb)
{
bomb.poof();
}

As the compiler is parsing line #2 , it must decide whether it is seeing a
declaration or a multiplication. This decision in turn depends on whether the
dependent qualified name Trap::x is a type name. It may be tempting to
look in the template Trap at this point and find that, according to line #1 ,
Trap::x is not a type, which would leave us to believe that line #2 is a
multiplication. However, a little later the source corrupts this idea by overriding
the generic Trap::x for the case where T is void. In this case,
Trap::x is in fact type int.
In this example, the type Trap is a dependent type because the type
depends on the template parameter T. Moreover, Trap refers to an
unknown specialization (described in Section 13.2.4 on page 223), which means
that the compiler cannot safely look inside the template to determine whether the
name Trap::x is a type or not. Had the type preceding the :: referred to a
current instantiation—for example, with Victim::y—the compiler could
have looked into the template definition because it is certain that no other
specialization could intervene. Thus, when the type preceding :: refers to the
current instantiation, qualified name lookup in a template behaves very similarly
to qualified name lookup for nondependent types.
However, as illustrated by the example, name lookup into an unknown

specialization is still a problem. The language definition resolves this problem
by specifying that in general a dependent qualified name does not denote a type
unless that name is prefixed with the keyword typename. If it turns out, after
substituting template arguments, that the name is not the name of a type, the
program is invalid and your C++ compiler should complain at instantiation time.
Note that this use of typename differs from the use to denote template type
parameters. Unlike type parameters, you cannot equivalently replace
typename with class.
The typename prefix to a name is required when the name satisfies all of the
following conditions:10
1. It is qualified and not itself followed by :: to form a more qualified name.
2. It is not part of an elaborated-type-specifier (i.e., a type name that starts with
one of the keywords class, struct, union, or enum).
3. It is not used in a list of base class specifications or in a list of member
initializers introducing a constructor definition.11
4. It is dependent on a template parameter.
5. It is a member of an unknown specialization, meaning that the type named by
the qualifier refers to an unknown specialization.
Furthermore, the typename prefix is not allowed unless at least the first two
previous conditions hold. To illustrate this, consider the following erroneous
example:12
Click here to view code image
template
struct S : typename2 X::Base {
S() : typename3 X::Base(typename4 X::Base(0)) {
}
typename5 X f() {
typename6 X::C * p; // declaration of pointer p
X::D * q; // multiplication!
}
typename7 X::C * s;
using Type = T;
using OtherType = typename8 S::Type;
};

Each occurrence of typename—correct or not—is numbered with a subscript
for easy reference. The first, typename1, indicates a template parameter. The
previous rules do not apply to this first use. The second and third typenames

are disallowed by the second item in the previous rules. Names of base classes in
these two contexts cannot be preceded by typename. However, typename4 is
required. Here, the name of the base class is not used to denote what is being
initialized or derived from. Instead, the name is part of an expression to
construct a temporary X::Base from its argument 0 (a sort of conversion,
if you will). The fifth typename is prohibited because the name that follows it,
X, is not a qualified name. The sixth occurrence is required if this statement
is to declare a pointer. The next line omits the typename keyword and is
therefore interpreted by the compiler as a multiplication. The seventh
typename is optional because it satisfies the first two rules but not the last two.
The eighth typename is also optional, because it refers to a member of a
current instantiation (and therefore does not satisfy the last rule).
The last of the rules for determining whether the typename prefix is
required can occasionally be tricky to evaluate, because it depends on the rules
for determining whether a type refers to a current instantiation or an unknown
specialization. In such cases, it is safest to simply add the typename keyword
to indicate that you intend the qualified name that follows to be a type. The
typename keyword, even if it’s optional, will provide documentation of your
intent.

13.3.3 Dependent Names of Templates
A problem very similar to the one encountered in the previous section occurs
when a name of a template is dependent. In general, a C++ compiler is required
to treat a < following the name of a template as the beginning of a template
argument list; otherwise, it is a less-than operator. As is the case with type
names, a compiler has to assume that a dependent name does not refer to a
template unless the programmer provides extra information using the keyword
template: Click here to view code image
template
class Shell {
public:
template
class In {
public:
template
class Deep {
public:
virtual void f();

};
};
};
template
class Weird {
public:
void case1 (
typename Shell::template In::template Deep* p) {
p->template Deep::f(); // inhibit virtual call
}
void case2 (
typename Shell::template In::template Deep& p) {
p.template Deep::f(); // inhibit virtual call
}
};

This somewhat intricate example shows how all the operators that can qualify a
name (::, ->, and .) may need to be followed by the keyword template.
Specifically, this is the case whenever the type of the name or expression
preceding the qualifying operator is dependent on a template parameter and
refers to an unknown specialization, and the name that follows the operator is a
template-id (in other words, a template name followed by template arguments in
angle brackets). For example, in the expression p.template
Deep::f()
the type of p depends on the template parameter T. Consequently, a C++
compiler cannot look up Deep to see if it is a template, and we must explicitly
indicate that Deep is the name of a template by inserting the prefix template.
Without this prefix, p.Deep::f() is parsed as ((p.Deep)f().
Note also that this may need to happen multiple times within a qualified name
because qualifiers themselves may be qualified with a dependent qualifier. (This
is illustrated by the declaration of the parameters of case1 and case2 in the
previous example.) If the keyword template is omitted in cases such as these,
the opening and closing angle brackets are parsed as less-than and greater-than
operators. As with the typename keyword, one can safely add the template
prefix to indicate that the following name is a template-id, even if the
template prefix is not strictly needed.

13.3.4 Dependent Names in Using Declarations
Using declarations can bring in names from two places: namespaces and classes.
The namespace case is not relevant in this context because there are no such

things as namespace templates. Using declarations that bring in names from
classes, on the other hand, can bring in names only from a base class to a derived
class. Such using declarations behave like “symbolic links” or “shortcuts” in the
derived class to the base declaration, thereby allowing the members of the
derived class to access the nominated name as if it were actually a member
declared in that derived class. A short nontemplate example illustrates the idea
better than mere words: class BX {
public:
void f(int);
void f(char const*);
void g();
};
class DX : private BX {
public:
using BX::f;
};
The previous using declaration brings in the name f of the base class BX into the
derived class DX. In this case, this name is associated with two different
declarations, thus emphasizing that we are dealing with a mechanism for names
and not individual declarations of such names. Note also that this kind of using
declaration can make accessible an otherwise inaccessible member. The base BX
(and thus its members) are private to the class DX, except that the functions
BX::f have been introduced in the public interface of DX and are therefore
available to the clients of DX.
By now you can probably perceive the problem when a using declaration
brings in a name from a dependent class. Although we know about the name, we
don’t know whether it’s the name of a type, a template, or something else: Click
here to view code image
template
class BXT {
public:
using Mystery = T;
template
struct Magic;
};
template
class DXTT : private BXT {
public:
using typename BXT::Mystery;

Mystery* p; // would be a syntax error without the earlier typename
};

Again, if we want a dependent name to be brought in by a using declaration to
denote a type, we must explicitly say so by inserting the keyword typename.
Strangely, the C++ standard does not provide for a similar mechanism to mark
such dependent names as templates. The following snippet illustrates the
problem: Click here to view code image
template
class DXTM : private BXT {
public:
using BXT::template Magic; // ERROR: not standard
Magic* plink; // SYNTAX ERROR: Magic is not a
}; // known template

The standardization committee has not been inclined to address this issue.
However, C++11 alias templates do provide a partial workaround: Click here to
view code image
template
class DXTM : private BXT {
public:
template
using Magic = typename BXT::template Magic; // Alias template
Magic* plink; // OK
};

This is a little unwieldy, but it achieves the desired effect for the case of class
templates. The case of function templates (arguably less common) remains
unaddressed, unfortunately.

13.3.5 ADL and Explicit Template Arguments
Consider the following example:
Click here to view code image
namespace N {
class X {
…
};
template void select(X*);
}
void g (N::X* xp)
{

select<3>(xp); // ERROR: no ADL!
}

In this example, we may expect that the template select() is found through
ADL in the call select<3>(xp). However, this is not the case because a
compiler cannot decide that xp is a function call argument until it has decided
that <3> is a template argument list. Furthermore, a compiler cannot decide that
<3> is a template argument list until it has found select() to be a template.
Because this chicken-and-egg problem cannot be resolved, the expression is
parsed as (select<3)>(xp), which makes no sense.
This example may give the impression that ADL is disabled for template-ids,
but it is not. The code can be fixed by introducing a function template named
select that is visible at the call: Click here to view code image
template void select(); Even though it doesn’t make any
sense for the call select<3>(xp), the presence of this function
template ensures that select<3> will be parsed as a template-id. ADL
will then find the function template N::select, and the call will
succeed.

13.3.6 Dependent Expressions
Like names, expressions themselves can be dependent on template parameters.
An expression that depends on a template parameter can behave differently from
one instantiation to the next—for example, selecting a different overloaded
function or producing a different type or constant value. Expressions that do not
depend on a template parameter, in contrast, provide the same behavior in all
instantiations.
An expression can be dependent on a template parameter in several different
ways. The most common form of dependent expression is a type-dependent
expression, where the type of the expression itself can vary from one
instantiation to the next—for example, an expression that refers to a function
parameter whose type is that of a template parameter: Click here to view code
image
template void typeDependent1(T x)
{
x; // the expression type-dependent, because the type of x can vary
}

Expressions that have type-dependent subexpressions are generally typedependent themselves—for example, calling a function f() with the argument

x: Click here to view code image
template void typeDependent2(T x)
{
f(x); // the expression is type-dependent, because x is typedependent
}

Here, note that type of f(x) can vary from one instantiation to the next both
because f might resolve to a template whose result type depends on the
argument type and because two-phase lookup (discussed in Section 14.3.1 on
page 249) might find completely different functions named f in different
instantiations.
Not all expressions that involve template parameters are type-dependent. For
example, an expression that involves template parameters can produce different
constant values from one instantiation to the next. Such expressions are called
value-dependent expressions, the simplest of which are those that refer to a
nontype template parameter of nondependent type. For example: Click here to
view code image
template void valueDependent1()
{
N; // the expression is value-dependent but not type-dependent,
// because N has a fixed type but a varying constant value
}

Like type-dependent expressions, an expression is generally value-dependent if
it is composed of other value-dependent expressions, so N + N or f(N) are
also value-dependent expressions.
Interestingly, some operations, such as sizeof, have a known result type, so
they can turn a type-dependent operand into a value-dependent expression that is
not type-dependent. For example: Click here to view code image
template void valueDependent2(T x)
{
sizeof(x); // the expression is value-dependent but not typedependent
}

The sizeof operation always produces a value of type std::size_t,
regardless of its input, so a sizeof expression is never type-dependent, even if
—as in this case—its subexpression is type-dependent. However, the resulting
constant value will vary from one instantiation to the next, so sizeof(x) is a
value-dependent expression.
What if we apply sizeof on a value-dependent expression?

Click here to view code image
template void maybeDependent(T const& x)
{
sizeof(sizeof(x));
}

Here, the inner sizeof expression is value-dependent, as noted above.
However, the outer sizeof expression always computes the size of a
std::size_t, so both its type and constant value are consistent across all
instantiations of the template, despite the innermost expression (x) being typedependent. Any expression that involves a template parameter is an
instantiation-dependent expression,13 even if both its type and constant value are
invariant across valid instantiations. However, an instantiation-dependent
expression may turn out to be invalid when instantiated. For example,
instantiating maybeDependent() with an incomplete class type will trigger
an error, because sizeof cannot be applied to such types.
Type-, value-, and instantiation-dependence can be thought of as a series of
increasingly more inclusive classifications of expressions. Any type-dependent
expression is also considered to be value-dependent, because an expression
whose type that varies from one instantiation to the next will naturally have its
constant value vary from one instantiation to the next. Similarly, an expression
whose type or value varies from one instantiation to the next depends on a
template parameter in some way, so both type-dependent expressions and valuedependent expressions are instantiation-dependent. This containment
relationship is illustrated by Figure 13.1.
Click here to view code image

Figure 13.1. Containment relationship among type-, value-, and instantiationdependent expressions
As one proceeds from the innermost context (type-dependent expressions) to
the outermost context, more of the behavior of the template is determined when
the template is parsed and therefore cannot vary from one instantiation to the
next. For example, consider the call f(x): If x is type-dependent, then f is a
dependent name that is subject to two-phase lookup (Section 14.3.1 on page
249), whereas if x is value-dependent but not type-dependent, f is a
nondependent name for which name lookup can be completely determined at the
time that the template is parsed.

13.3.7 Compiler Errors
A C++ compiler is permitted (but not required!) to diagnose errors at the time the
template is parsed when all of the instantiations of the template would produce
that error. Let’s expand on the f(x) example from the previous section to
explore this further: Click here to view code image
void f() { }
template void nondependentCall()
{
f(x); // x is value-dependent, so f() is nondependent;
// this call will never succeed
}

Here, the call f(x) will produce an error in every instantiation because f is a
nondependent name and the only visible f accepts zero arguments, not one. A
C++ compiler can produce an error when parsing the template or may wait until
the first template instantiation: Commonly used compilers differ even on this
simple example. One can construct similar examples with expressions that are
instantiation-dependent but not value-dependent: Click here to view code image
template void instantiationDependentBound()
{
constexpr int x = sizeof(N);
constexpr int y = sizeof(N) + 1;
int array[x - y]; // array will have a negative size in all
instantiations
}

13.4 Inheritance and Class Templates
Class templates can inherit or be inherited from. For many purposes, there is
nothing significantly different between the template and nontemplate scenarios.
However, there is one important subtlety when deriving a class template from a
base class referred to by a dependent name. Let’s first look at the somewhat
simpler case of nondependent base classes.

13.4.1 Nondependent Base Classes
In a class template, a nondependent base class is one with a complete type that

can be determined without knowing the template arguments. In other words, the
name of this base is denoted using a nondependent name. For example: Click
here to view code image
template
class Base {
public:
int basefield;
using T = int;
};
class D1: public Base> { //not a template case really
public:
void f() { basefield = 3; } //usual access to inherited member
};
template
class D2 : public Base { //nondependent base
public:
void f() { basefield = 7; } //usual access to inherited member
T strange; // T is Base::T, not the template parameter!
};

Nondependent bases in templates behave very much like bases in ordinary
nontemplate classes, but there is a slightly unfortunate surprise: When an
unqualified name is looked up in the templated derivation, the nondependent
bases are considered before the list of template parameters. This means that in
the previous example, the member strange of the class template D2 always
has the type T corresponding to Base::T (in other words, int).
For example, the following function is not valid C++ (assuming the previous
declarations): Click here to view code image
void g (D2& d2, int* p)
{
d2.strange = p; // ERROR: type mismatch!
}

This is counterintuitive and requires the writer of the derived template to be
aware of names in the nondependent bases from which it derives—even when
that derivation is indirect or the names are private. It would probably have been
preferable to place template parameters in the scope of the entity they
“templatize.”

13.4.2 Dependent Base Classes

In the previous example, the base class is fully determined. It does not depend on
a template parameter. This implies that a C++ compiler can look up
nondependent names in those base classes as soon as the template definition is
seen. An alternative—not allowed by the C++ standard—would consist in
delaying the lookup of such names until the template is instantiated. The
disadvantage of this alternative approach is that it also delays any error messages
resulting from missing symbols until instantiation. Hence, the C++ standard
specifies that a nondependent name appearing in a template is looked up as soon
as it is encountered. Keeping this in mind, consider the following example: Click
here to view code image
template
class DD : public Base { //dependent base
public:
void f() { basefield = 0; } // #1 problem…
};
template<> // explicit specialization
class Base {
public:
enum { basefield = 42 }; // #2 tricky!
};
void g (DD& d)
{
d.f(); // #3 oops?
}

At point #1 we find our reference to a nondependent name basefield: It must
be looked up right away. Suppose we look it up in the template Base and bind it
to the int member that we find therein. However, shortly after this we override
the generic definition of Base with an explicit specialization. As it happens, this
specialization changes the meaning of the basefield member to which we
already committed! So, when we instantiate the definition of DD::f at point #3
, we find that we too eagerly bound the nondependent name at point #1 . There is
no modifiable basefield in DD that was specialized at point #2 , and
an error message should have been issued.
To circumvent this problem, standard C++ says that nondependent names are
not looked up in dependent base classes14 (but they are still looked up as soon as
they are encountered). So, a standard C++ compiler will emit a diagnostic at
point #1 . To correct the code, it suffices to make the name basefield
dependent because dependent names can be looked up only at the time of
instantiation, and at that time the concrete base instance that must be explored

will be known. For example, at point #3 , the compiler will know that the base
class of DD is Base and that this has been explicitly
specialized by the programmer. In this case, our preferred way to make the name
dependent is as follows: Click here to view code image
// Variation 1:
template
class DD1 : public Base {
public:
void f() { this->basefield = 0; } //lookup delayed
};

An alternative consists in introducing a dependency using a qualified name:
Click here to view code image
// Variation 2:
template
class DD2 : public Base {
public:
void f() { Base::basefield = 0; }
};

Care must be taken with this solution, because if the unqualified nondependent
name is used to form a virtual function call, then the qualification inhibits the
virtual call mechanism and the meaning of the program changes. Nonetheless,
there are situations when the first variation cannot be used and this alternative is
appropriate: Click here to view code image
template
class B {
public:
enum E { e1 = 6, e2 = 28, e3 = 496 };
virtual void zero(E e = e1);
virtual void one(E&);
};
template
class D : public B {
public:
void f() {
typename D::E e; // this->E would not be valid syntax
this->zero(); // D::zero() would inhibit virtuality
one(e); // one is dependent because its argument
} //is dependent
};

Note how we used D::E instead of B::E in this example. In this case,
either one works. In multiple-inheritance cases, however, we may not know
which base class provides the desired member (in which case using the derived

class for qualification works) or multiple base classes may declare the same
name (in which case we may have to use a specific base class name for
disambiguation).
Note that the name one in the call one(e) is dependent on the template
parameter simply because the type of one of the call’s explicit arguments is
dependent. Implicitly used default arguments with a type that depends on a
template parameter do not count because the compiler cannot verify this until it
already has decided the lookup—a chicken-and-egg problem. To avoid subtlety,
we prefer to use the this-> prefix in all situations that allow it—even for
nontemplate code.
If you find that the repeated qualifications are cluttering up your code, you can
bring a name from a dependent base class in the derived class once and for all:
Click here to view code image
// Variation 3:
template
class DD3 : public Base {
public:
using Base::basefield; // #1 dependent name now in scope
void f() { basefield = 0; } // #2 fine
};

The lookup at point #2 succeeds and finds the using declaration of point #1 .
However, the using declaration is not verified until instantiation time and our
goal is achieved. There are some subtle limitations to this scheme. For example,
if multiple bases are derived from, the programmer must select exactly which
one contains the desired member.
When searching for a qualified name within the current instantiation, the C++
standard specifies that name lookup first search in the current instantiation and in
all nondependent bases, similar to the way it performs unqualified lookup for
that name. If any name is found, then the qualified name refers to a member of a
current instantiation and will not be a dependent name.15 If no such name is
found, and the class has any dependent bases, then the qualified name refers to a
member of an unknown specialization. For example: Click here to view code
image
class NonDep {
public:
using Type = int;
};
template
class Dep {
public:

using OtherType = T;
};
template
class DepBase : public NonDep, public Dep {
public:
void f() {
typename DepBase::Type t; // finds NonDep::Type;
// typename keyword is optional
typename DepBase::OtherType* ot; // finds nothing;
DepBase::OtherType
// is a member of an unknown specialization
}
};

13.5 Afternotes
The first compiler really to parse template definitions was developed by a
company called Taligent in the mid-1990s. Before that—and even several years
after that—most compilers treated templates as a sequence of tokens to be
played back through the parser at instantiation time. Hence no parsing was done,
except for a minimal amount sufficient to find the end of a template definition.
At the time of this writing, the Microsoft Visual C++ compiler still works this
way. The Edison Design Group’s (EDG’s) compiler front end uses a hybrid
technique where templates are treated internally as a sequence of annotated
tokens, but a “generic parsing” is performed to validate the syntax in modes
where that is desirable (EDG’s product emulates multiple other compilers; in
particular, it can closely emulate the behavior of Microsoft’s compiler).
Bill Gibbons was Taligent’s representative to the C++ committee and was the
principal advocate for making templates unambiguously parsable. The Taligent
effort was not released until the compiler was acquired and completed by
Hewlett-Packard (HP), to become the aC++ compiler. Among its competitive
advantages, the aC++ compiler was quickly recognized for its high-quality
diagnostics. The fact that template diagnostics were not always delayed until
instantiation time undoubtedly contributed to this perception.
Relatively early during the development of templates, Tom Pennello—a
widely recognized parsing expert working for Metaware—noted some of the
problems associated with angle brackets. Stroustrup also comments on that topic
in [StroustrupDnE] and argues that humans prefer to read angle brackets rather
than parentheses. However, other possibilities exist, and Pennello specifically
proposed braces (e.g., List{::X}) at a C++ standards meeting in 1991 (held in

Dallas).16 At that time the extent of the problem was more limited because
templates nested inside other templates—called member templates—were not
valid, and thus the discussion of Section 13.3.3 on page 230 was largely
irrelevant. As a result, the committee declined the proposal to replace the angle
brackets.
The name lookup rule for nondependent names and dependent base classes
that is described in Section 13.4.2 on page 237 was introduced in the C++
standard in 1993. It was described to the “general public” in Bjarne Stroustrup’s
[StroustrupDnE] in early 1994. Yet the first generally available implementation
of this rule did not appear until early 1997 when HP incorporated it into their
aC++ compiler, and by then large amounts of code derived class templates from
dependent bases. Indeed, when the HP engineers started testing their
implementation, they found that most of the programs that used templates in
nontrivial ways no longer compiled.17 In particular, all implementations of the
Standard Template Library (STL) broke the rule in many hundreds—and
sometimes thousands—of places.18 To ease the transition process for their
customers, HP softened the diagnostic associated with code that assumed that
nondependent names could be found in dependent base classes as follows: When
a nondependent name used in the scope of a class template is not found using the
standard rules, aC++ peeks inside the dependent bases. If the name is still not
found, a hard error is issued and compilation fails. However, if the name is found
in a dependent base, a warning is issued, and the name is marked to be treated as
if it were dependent, so that lookup will be reattempted at instantiation time.
The lookup rule that causes a name in nondependent bases to hide an
identically named template parameter (Section 13.4.1 on page 236) is an
oversight, but suggestions to change the rule have not garnered support from the
C++ standardization committee. It is best to avoid code with template parameter
names that are also used in nondependent base classes. Good naming
conventions are helpful for such problems.
Friend name injection was considered harmful because it made the validity of
programs more sensitive to the ordering of instantiations. Bill Gibbons (who at
the time was working on the Taligent compiler) was among the most vocal
supporters of addressing the problem, because eliminating instantiation order
dependencies enabled new and interesting C++ development environments (on
which Taligent was rumored to be working). However, the Barton-Nackman
trick (Section 21.2.1 on page 497) required a form of friend name injection, and
it is this particular technique that caused it to remain in the language in its
current (weakened) form based on ADL.

Andrew Koenig first proposed ADL for operator functions only (which is why
ADL is sometimes called Koenig lookup). The motivation was primarily
aesthetics: Explicitly qualifying operator names with their enclosing namespace
looks awkward at best (e.g., instead of a+b we may need to write
N::operator+(a, b)), and having to write using declarations for every
operator can lead to unwieldy code. Hence, it was decided that operators would
be looked up in the namespaces associated with arguments. ADL was later
extended to ordinary function names to accommodate a limited kind of friend
name injection and to support a two-phase lookup model for templates and their
instantiations (Chapter 14). The generalized ADL rules are also called extended
Koenig lookup.
The specification for the angle bracket hack was added to C++11 by David
Vandevoorde through his paper N1757. He also added the digraph hack via the
resolution of Core issue 1104, to address a request of the United States’ review
of a draft of the C++11 standard.
2 In C++98/C++03, this was also called Koenig lookup (or extended Koenig
lookup) after Andrew Koenig, who first proposed a variation of this
mechanism.
3 Although this was clearly intended by those who wrote the C++ standard, it is
not clearly spelled out in the standard.
4 Note the double parentheses to avoid parsing (Invert<1>)0 as a cast
operation—yet another source of syntactic ambiguity.
5 Specific exceptions were introduced to address tokenization issues described
in this section.
6 The 1998 and 2003 versions of the C++ standard did not support this “angle
bracket hack.” However, the need to introduce a space between the two
consecutive right angle brackets was such a common stumbling block for
beginning template users that the committee decided to codify this hack in the
2011 standard.
7 Some compilers that provide a C++98 or C++03 mode keep the C++11
behavior in those modes and thus print 0 0 even when formally compiling
C++98/C++03 code.
8 This is therefore an exception to the aforementioned maximum munch
principle.
9 Thanks to Richard Smith for pointing that out.
10 Note that C++20 will probably remove the need for typename in most cases
(see Section 17.1 on page 354 for details).

11

Syntactically, only type names are permitted within these contexts, so a
qualified name is always assumed to name a type.
12 Adapted from [VandevoordeSolutions], proving once and for all that C++
promotes code reuse.
13 The terms type-dependent expression and value-dependent expression are used
in the C++ standard to describe the semantics of templates, and they have an
effect on several aspects of template instantiation (Chapter 14). On the other
hand, the term instantiation-dependent expression is mainly only used by the
authors of C++ compilers. Our definition of a instantiation-dependent
expression comes from the Itanium C++ ABI [ItaniumABI], which provides
the basis for binary interoperability among a number of different C++
compilers.
14 This is part of the two-phase lookup rules that distinguish between a first phase
when template definitions are first seen and a second phase when templates are
instantiated (see Section 14.3.1 on page 249).
15 However, the lookup is nonetheless repeated when the template is instantiated,
and if a different result is produced in that context, the program is ill-formed.
16 Braces are not entirely without problems either. Specifically, the syntax to
specialize class templates would require nontrivial adaptation.
17 Fortunately, they found out before they released the new functionality.
18 Ironically, the first of these implementations had been developed by HP as
well.

Chapter 14
Instantiation
Template instantiation is the process that generates types, functions, and
variables from generic template definitions.1 The concept of instantiation of C++
templates is fundamental but also somewhat intricate. One of the underlying
reasons for this intricacy is that the definitions of entities generated by a
template are no longer limited to a single location in the source code. The
location of the template, the location where the template is used, and the
locations where the template arguments are defined all play a role in the meaning
of the entity.
In this chapter we explain how we can organize our source code to enable
proper template use. In addition, we survey the various methods that are used by
the most popular C++ compilers to handle template instantiation. Although all
these methods should be semantically equivalent, it is useful to understand basic
principles of the compiler’s instantiation strategy. Each mechanism comes with
its set of little quirks when building real-life software and, conversely, each
influenced the final specifications of standard C++.

14.1 On-Demand Instantiation
When a C++ compiler encounters the use of a template specialization, it will
create that specialization by substituting the required arguments for the template
parameters.2 This is done automatically and requires no direction from the client
code (or from the template definition, for that matter). This on-demand
instantiation feature sets C++ templates apart from similar facilities in other
early compiled languages (like Ada or Eiffel; some of these languages require
explicit instantiation directives, whereas others use run-time dispatch
mechanisms to avoid the instantiation process altogether). It is sometimes also
called implicit or automatic instantiation.
On-demand instantiation implies that the compiler often needs access to the
full definition (in other words, not just the declaration) of the template and some

of its members at the point of use. Consider the following tiny source code file:
Click here to view code image
template class C; // #1 declaration only
C* p = 0; // #2 fine: definition of C not needed
template
class C {
public:
void f(); // #3 member declaration
}; // #4 class template definition completed
void g (C& c) // #5 use class template declaration only
{
c.f(); // #6 use class template definition;
} // will need definition of C::f()
// in this translation unit
template
void C::f() //required definition due to #6
{
}

At point #1 in the source code, only the declaration of the template is available,
not the definition (such a declaration is sometimes called a forward declaration).
As is the case with ordinary classes, we do not need the definition of a class
template to be visible to declare pointers or references to this type, as was done
at point #2 . For example, the type of the parameter of function g() does not
require the full definition of the template C. However, as soon as a component
needs to know the size of a template specialization or if it accesses a member of
such a specialization, the entire class template definition is required to be visible.
This explains why at point #6 in the source code, the class template definition
must be seen; otherwise, the compiler cannot verify that the member exists and
is accessible (not private or protected). Furthermore, the member function
definition is needed too, since the call at point #6 requires C::f() to
exist.
Here is another expression that needs the instantiation of the previous class
template because the size of C is needed: C* p = new
C;
In this case, instantiation is needed so that the compiler can determine the size of
C, which the new-expression needs to determine how much storage to
allocate. You might observe that for this particular template, the type of the
argument X substituted for T will not influence the size of the template because
in any case, C is an empty class. However, a compiler is not required to
avoid instantiation by analyzing the template definition (and all compilers do

perform the instantiation in practice). Furthermore, instantiation is also needed in
this example to determine whether C has an accessible default
constructor and to ensure C does not declare member operators new or
delete.
The need to access a member of a class template is not always very explicitly
visible in the source code. For example, C++ overload resolution requires
visibility into class types for parameters of candidate functions: Click here to
view code image
template
class C {
public:
C(int); // a constructor that can be called with a single parameter
}; // may be used for implicit conversions
void candidate(C); // #1
void candidate(int) { } // #2
int main()
{
candidate(42); // both previous function declarations can be called
}

The call candidate(42) will resolve to the overloaded declaration at point
#2 . However, the declaration at point #1 could also be instantiated to check
whether it is a viable candidate for the call (it is in this case because the oneargument constructor can implicitly convert 42 to an rvalue of type
C). Note that the compiler is allowed (but not required) to perform
this instantiation if it can resolve the call without it (as could be the case in this
example because an implicit conversion would not be selected over an exact
match). Note also that the instantiation of C could trigger an error,
which may be surprising.

14.2 Lazy Instantiation
The examples so far illustrate requirements that are not fundamentally different
from the requirements when using nontemplate classes. Many uses require a
class type to be complete (see Section 10.3.1 on page 154). For the template
case, the compiler will generate this complete definition from the class template
definition.
A pertinent question now arises: How much of the template is instantiated? A

vague answer is the following: Only as much as is really needed. In other words,
a compiler should be “lazy” when instantiating templates. Let’s look at exactly
what this laziness entails.

14.2.1 Partial and Full Instantiation
As we have seen, the compiler sometimes doesn’t need to substitute the
complete definition of a class or function template. For example: Click here to
view code image
template T f (T p) { return 2*p; }
decltype(f(2)) x = 2; In this example, the type indicated by
decltype(f(2)) does not require the complete instantiation of the
function template f(). A compiler is therefore only permitted to
substitute the declaration of f(), but not its “body.” This is
sometimes called partial instantiation.

Similarly, if an instance of a class template is referred to without the need for
that instance to be a complete type, the compiler should not perform a complete
instantiation of that class template instance. Consider the following example:
Click here to view code image
template class Q {
using Type = typename T::Type;
};
Q* p = 0; // OK: the body of Q is not substituted

Here, the full instantiation of Q would trigger an error, because
T::Type doesn’t make sense when T is int. But because Q need not
be complete in this example, no full instantiation is performed and the code is
okay (albeit suspicious).
Variable templates also have a “full” vs. “partial” instantiation distinction. The
following example illustrates it: Click here to view code image
template T v = T::default_value();
decltype(v) s; // OK: initializer of v not instantiated

A full instantiation of v would elicit an error, but that is not needed if we
only need the type of the variable template instance.
Interestingly, alias templates do not have this distinction: There are no two
ways of substituting them.
In C++, when speaking about “template instantiation” without being specific
about full or partial instantiation, the former is intended. That is, instantiation is

full instantiation by default.

14.2.2 Instantiated Components
When a class template is implicitly (fully) instantiated, each declaration of its
members is instantiated as well, but the corresponding definitions are not (i.e.,
the member are partially instantiated). There are a few exceptions to this. First, if
the class template contains an anonymous union, the members of that union’s
definition are also instantiated.3 The other exception occurs with virtual member
functions. Their definitions may or may not be instantiated as a result of
instantiating a class template. Many implementations will, in fact, instantiate the
definition because the internal structure that enables the virtual call mechanism
requires the virtual functions actually to exist as linkable entities.
Default function call arguments are considered separately when instantiating
templates. Specifically, they are not instantiated unless there is a call to that
function (or member function) that actually makes use of the default argument.
If, on the other hand, the function is called with explicit arguments that override
the default, then the default arguments are not instantiated.
Similarly, exception specifications and default member initializers are not
instantiated unless they are needed.
Let’s put together some examples that illustrate some of these principles:
Click here to view code image
details/lazy1.hpp
template
class Safe {
};
template
class Danger {
int arr[N]; // OK here, although would fail for N<=0
};
template
class Tricky {
public:
void noBodyHere(Safe = 3); // OK until usage of default value
results in an error
void inclass() {
Danger noBoomYet; // OK until inclass() is used with N<=0
}

struct Nested {
Danger pfew; // OK until Nested is used with N<=0
};
union { //due anonymous union:
Danger anonymous; // OK until Tricky is instantiated with N<=0
int align;
};
void unsafe(T (*p)[N]); // OK until Tricky is instantiated with N<=0
void error() {
Danger<-1> boom; // always ERROR (which not all compilers detect)
}
};

A standard C++ compiler will examine these template definitions to check the
syntax and general semantic constraints. While doing so, it will “assume the
best” when checking constraints involving template parameters. For example,
the parameter N in the member Danger::arr could be zero or negative
(which would be invalid), but it is assumed that this isn’t the case.4 The
definitions of inclass(), struct Nested, and the anonymous union are
thus not a problem.
For the same reason, the declaration of the member unsafe(T (*p)[N])
is not a problem, as long as N is an unsubstituted template parameter.
The default argument specification (= 3) on the declaration of the member
noBodyHere() is suspicious because the template Safe<> isn’t initializable
with an integer, but the assumption is that either the default argument won’t
actually be needed for the generic definition of Safe or that Safe will
be specialized (see Chapter 16) to enable initialization with an integer value.
However, the definition of the member function error() is an error even when
the template is not instantiated, because the use of Danger<-1> requires a
complete definition of the class Danger<-1>, and generating that class runs
into an attempt to define an array with negative size. Interestingly, while the
standard clearly states that this code is invalid, it also allows compilers not to
diagnose the error when the template instance is not actually used. That is, since
Tricky::error() is not used for any concrete T and N, a compiler is
not required to issue an error for this case. For example, GCC and Visual C++ do
not diagnose this error at the time of this writing.
Now let’s analyze what happens when we add the following definition:
Tricky inst; This causes the compiler to (fully) instantiate
Tricky by substituting int for T and -1 for N in the definition
of template Tricky<>. Not all the member definitions will be needed, but the
default constructor and the destructor (both implicitly declared in this case) are

definitely called, and hence their definitions must be available somehow (which
is the case in our example, since they are implicitly generated). As explained
above, the members of Tricky are partially instantiated (i.e., their
declarations are substituted): That process can potentially result in errors. For
example, the declaration of unsafe(T (*p)[N]) creates an array type with
a negative of number elements, and that is an error. Similarly, the member
anonymous now triggers an error, because type Danger<-1> cannot be
completed. In contrast, the definitions of the members inclass() and
struct Nested are not yet instantiated, and thus no errors occur from their
need for the complete type Danger<-1> (which contains an invalid array
definition as we discussed earlier).
As written, when instantiating a template, in practice, the definitions of virtual
members should also be provided. Otherwise, linker errors are likely to occur.
For example: Click here to view code image
details/lazy2.cpp
template
class VirtualClass {
public:
virtual ~VirtualClass() {}
virtual T vmem(); // Likely ERROR if instantiated without definition
};
int main()
{
VirtualClass inst;
}

Finally, a note about operator->. Consider: template
class C {
public:
T operator-> ();
};
Normally, operator-> must return a pointer type or another class type to
which operator-> applies. This suggests that the completion of C
triggers an error, because it declares a return type of int for operator->.
However, because certain natural class template definitions trigger these kinds of
definitions,5 the language rule is more flexible. A user-defined operator-> is
only required to return a type to which another (e.g., built-in) operator->
applies if that operator is actually selected by overload resolution. This is true

even outside templates (although the relaxed behavior is less useful in those
contexts). Hence, the declaration here triggers no error, even though int is
substituted for the return type.

14.3 The C++ Instantiation Model
Template instantiation is the process of obtaining a regular type, function, or
variable from a corresponding template entity by appropriately substituting the
template parameters. This may sound fairly straightforward, but in practice many
details need to be formally established.

14.3.1 Two-Phase Lookup
In Chapter 13 we saw that dependent names cannot be resolved when parsing
templates. Instead, they are looked up again at the point of instantiation.
Nondependent names, however, are looked up early so that many errors can be
diagnosed when the template is first seen. This leads to the concept of two-phase
lookup:6 The first phase is the parsing of a template, and the second phase is its
instantiation: 1. During the first phase, while parsing a template, nondependent
names are looked up using both the ordinary lookup rules and, if applicable, the
rules for argument-dependent lookup (ADL). Unqualified dependent names
(which are dependent because they look like the name of a function in a function
call with dependent arguments) are looked up using the ordinary lookup rules,
but the result of the lookup is not considered complete until an additional lookup
is performed in the second phase (when the template is instantiated).
2. During the second phase, while instantiating a template at a point called the
point of instantiation (POI), dependent qualified names are looked up (with
the template parameters replaced with the template arguments for that specific
instantiation), and an additional ADL is performed for the unqualified
dependent names that were looked up using ordinary lookup in the first phase.
For unqualified dependent names, the initial ordinary lookup—while not
complete—is used to decide whether the name is a template. Consider the
following example: Click here to view code image
namespace N {
template void g() {}
enum E { e };

}
template void f() {}
template void h(T P) {
f(p); // #1
g(p); // #2 ERROR
}
int main() {
h(N::e); // calls template h with T = N::E
}

In line #1 , when seeing the name f followed by a <, the compiler has to decide
whether that < is an angle bracket or a less-than sign. That depends on whether
f is known to be the name of a template or not; in this case, ordinary lookup
finds the declaration of f, which is indeed a template, and so parsing succeeds
with angle brackets.
Line #2 , however, produces an error because no template g is found using
ordinary lookup; the < is thus treated as a less-than sign, which is a syntax error
in this example. If we could get past this issue, we’d eventually find the template
N::g using ADL when instantiating h for T = N::E (since N is a namespace
associated with E), but we cannot get that far until we successfully parse the
generic definition of h.

14.3.2 Points of Instantiation
We have already illustrated that there are points in the source of template clients
where a C++ compiler must have access to the declaration or the definition of a
template entity. A point of instantiation (POI) is created when a code construct
refers to a template specialization in such a way that the definition of the
corresponding template needs to be instantiated to create that specialization. The
POI is a point in the source where the substituted template could be inserted. For
example: Click here to view code image
class MyInt {
public:
MyInt(int i);
};
MyInt operator - (MyInt const&);
bool operator > (MyInt const&, MyInt const&);

using Int = MyInt;
template
void f(T i)
{
if (i>0) {
g(-i);
}
}
// #1
void g(Int)
{
// #2
f(42); // point of call
// #3
}
// #4

When a C++ compiler sees the call f(42), it knows the template f will
need to be instantiated for T substituted with MyInt: A POI is created. Points #2
and #3 are very close to the point of call, but they cannot be POIs because C++
does not allow us to insert the definition of ::f(Int) there. The
essential difference between point #1 and point #4 is that at point #4 the function
g(Int) is visible, and hence the template-dependent call g(-i) can be
resolved. However, if point #1 were the POI, then that call could not be resolved
because g(Int) is not yet visible. Fortunately, C++ defines the POI for a
reference to a function template specialization to be immediately after the
nearest namespace scope declaration or definition that contains that reference. In
our example, this is point #4 .
You may wonder why this example involved the type MyInt rather than
simple int. The answer lies in the fact that the second lookup performed at the
POI is only an ADL. Because int has no associated namespace, the POI lookup
would therefore not take place and would not find function g. Hence, if we were
to replace the type alias declaration for Int with using Int = int; the previous
example would no longer compile. The following example suffers from a similar
problem: Click here to view code image
template
void f1(T x)
{
g1(x); // #1
}
void g1(int)
{

}
int main()
{
f1(7); // ERROR: g1 not found!
}
// #2 POI for f1(int)

The call f1(7) creates a POI for f1(int) just outside of main() at
point #2 . In this instantiation, the key issue is the lookup of function g1. When
the definition of the template f1 is first encountered, it is noted that the
unqualified name g1 is dependent because it is the name of a function in a
function call with dependent arguments (the type of the argument x depends on
the template parameter T). Therefore, g1 is looked up at point #1 using ordinary
lookup rules; however, no g1 is visible at this point. At point #2 , the POI, the
function is looked up again in associated namespaces and classes, but the only
argument type is int, and it has no associated namespaces and classes.
Therefore, g1 is never found even though ordinary lookup at the POI would
have found g1.
The point of instantiation for variable templates is handled similarly to that of
function templates.7 For class template specializations, the situation is different,
as the following example illustrates: Click here to view code image
template
class S {
public:
T m;
};
// #1
unsigned long h()
{
// #2
return (unsigned long)sizeof(S);
// #3
}
// #4

Again, the function scope points #2 and #3 cannot be POIs because a definition
of a namespace scope class S cannot appear there (and templates can
generally not appear in function scope8). If we were to follow the rule for
function template instances, the POI would be at point #4 , but then the
expression sizeof(S) is invalid because the size of S cannot
be determined until point #4 is reached. Therefore, the POI for a reference to a
generated class instance is defined to be the point immediately before the nearest
namespace scope declaration or definition that contains the reference to that

instance. In our example, this is point #1 .
When a template is actually instantiated, the need for additional instantiations
may appear. Consider a short example: Click here to view code image
template
class S {
public:
using I = int;
};
// #1
template
void f()
{
S::I var1 = 41;
typename S::I var2 = 42;
}
int main()
{
f();
}
// #2 : #2a , #2b

Our preceding discussion already established that the POI for f() is
at point #2 . The function template f() also refers to the class specialization
S with a POI that is therefore at point #1 . It references S too, but
because this is still dependent, we cannot really instantiate it at this point.
However, if we instantiate f() at point #2 , we notice that we also
need to instantiate the definition of S. Such secondary or transitive
POIs are defined slightly differently. For function templates, the secondary POI
is exactly the same as the primary POI. For class entities, the secondary POI
immediately precedes (in the nearest enclosing namespace scope) the primary
POI. In our example, this means that the POI of f() can be placed
at point #2b , and just before it—at point #2a —is the secondary POI for
S. Note how this differs from the POI for S.
A translation unit often contains multiple POIs for the same instance. For class
template instances, only the first POI in each translation unit is retained, and the
subsequent ones are ignored (they are not really considered POIs). For instances
of function and variable templates, all POIs are retained. In either case, the ODR
requires that the instantiations occurring at any of the retained POIs be
equivalent, but a C++ compiler does not need to verify and diagnose violations
of this rule. This allows a C++ compiler to pick just one nonclass POI to perform
the actual instantiation without worrying that another POI might result in a

different instantiation.
In practice, most compilers delay the actual instantiation of most function
templates to the end of the translation unit. Some instantiations cannot be
delayed, including cases where instantiation is needed to determine a deduced
return type (see Section 15.10.1 on page 296 and Section 15.10.4 on page 303)
and cases where the function is constexpr and must be evaluated to produce a
constant result. Some compilers instantiate inline functions when they’re first
used to potentially inline the call right away.9 This effectively moves the POIs of
the corresponding template specializations to the end of the translation unit,
which is permitted by the C++ standard as an alternative POI.

14.3.3 The Inclusion Model
Whenever a POI is encountered, the definition of the corresponding template
must somehow be accessible. For class specializations this means that the class
template definition must have been seen earlier in the translation unit. For the
POIs of function and variable templates (and member functions and static data
members of class templates) this is also needed, and typically template
definitions are simply added to header files that are #included into the
translation unit, even when they’re nontype templates. This source model for
template definitions is called the inclusion model, and it is the only automatic
source model for templates supported by the current C++ standard.10
Although the inclusion model encourages programmers to place all their
template definitions in header files so that they are available to satisfy any POIs
that may arise, it is also possible to explicitly manage instantiations using
explicit instantiation declarations and explicit instantiation definitions (see
Section 14.5 on page 260). Doing so is logistically not trivial and most of the
time programmers will prefer to rely on the automatic instantiation mechanism
instead. One challenge for an implementation with the automatic scheme is to
deal with the possibility of having POIs for the same specialization of a function
or variable templates (or the same member function or static data member of a
class template instance) across different translation units. We discuss approaches
to this problem next.

14.4 Implementation Schemes

In this section we review some ways in which C++ implementations support the
inclusion model. All these implementations rely on two classic components: a
compiler and a linker. The compiler translates source code to object files, which
contain machine code with symbolic annotations (cross-referencing other object
files and libraries). The linker creates executable programs or libraries by
combining the object files and resolving the symbolic cross-references they
contain. In what follows, we assume such a model even though it is entirely
possible (but not popular) to implement C++ in other ways. For example, one
might imagine a C++ interpreter.
When a class template specialization is used in multiple translation units, a
compiler will repeat the instantiation process in every translation unit. This poses
very few problems because class definitions do not directly create low-level
code. They are used only internally by a C++ implementation to verify and
interpret various other expressions and declarations. In this regard, the multiple
instantiations of a class definition are not materially different from the multiple
inclusions of a class definition— typically through header file inclusion—in
various translation units.
However, if you instantiate a (noninline) function template, the situation may
be different. If you were to provide multiple definitions of an ordinary noninline
function, you would violate the ODR. Assume, for example, that you compile
and link a program consisting of the following two files: // ==== a.cpp:
int main()
{
}
// ==== b.cpp:
int main()
{
}
C++ compilers will compile each module separately without any problems
because indeed they are valid C++ translation units. However, your linker will
most likely protest if you try to link the two together: Duplicate definitions are
not allowed.
In contrast, consider the template case:
Click here to view code image
// ==== t.hpp:
// common header (inclusion model)
template
class S {

public:
void f();
};
template
void S::f() //member definition
{
}
void helper(S*);
// ==== a.cpp:
#include "t.hpp"
void helper(S* s)
{
s->f(); // #1 first point of instantiation of S::f
}
// ==== b.cpp:
#include "t.hpp"
int main()
{
S s;
helper(&s);
s.f(); // #2 second point of instantiation of S::f
}

If the linker treats instantiated member functions of class templates just like it
does for ordinary functions or member functions, the compiler needs to ensure
that it generates code at only one of the two POIs: at points #1 or #2 , but not
both. To achieve this, a compiler has to carry information from one translation
unit to the other, and this is something C++ compilers were never required to do
prior to the introduction of templates. In what follows, we discuss the three
broad classes of solutions that have been used by C++ implementers.
Note that the same problem occurs with all linkable entities produced by
template instantiation: instantiated function templates and member function
templates, as well as instantiated static data members and instantiated variable
templates.

14.4.1 Greedy Instantiation
The first C++ compilers that popularized greedy instantiation were produced by
a company called Borland. It has grown to be by far the most commonly used
technique among the various C++ systems.
Greedy instantiation assumes that the linker is aware that certain entities—

linkable template instantiations in particular—may in fact appear in duplicate
across the various object files and libraries. The compiler will typically mark
these entities in a special way. When the linker finds multiple instances, it keeps
one and discards all the others. There is not much more to it than that.
In theory, greedy instantiation has some serious drawbacks: • The compiler
may be wasting time on generating and optimizing N instantiations, of which
only one will be kept.
• Linkers typically do not check that two instantiations are identical because
some insignificant differences in generated code can validly occur for multiple
instances of one template specialization. These small differences should not
cause the linker to fail. (These differences could result from tiny differences in
the state of the compiler at the instantiation times.) However, this often also
results in the linker not noticing more substantial differences, such as when one
instantiation was compiled with strict floating-point math rules whereas the
other was compiled with relaxed, higher-performance floating-point math
rules.11
• The sum of all the object files could potentially be much larger than with
alternatives because the same code may be duplicated many times.
In practice, these shortcomings do not seem to have caused major problems.
Perhaps this is because greedy instantiation contrasts very favorably with the
alternatives in one important aspect: The traditional source-object dependency is
preserved. In particular, one translation unit generates but one object file, and
each object file contains compiled code for all the linkable definitions in the
corresponding source file (which includes the instantiated definitions). Another
important benefit is that all function template instances are candidates for
inlining without resorting to expensive “link-time” optimization mechanisms
(and, in practice, function template instances are often small functions that
benefit from inlining). The other instantiation mechanisms treat inline function
template instances specially to ensure they can be expanded inline. However,
greedy instantiation allows even noninline function template instances to be
expanded inline.
Finally, it may be worth noting that the linker mechanism that allows duplicate
definitions of linkable entities is also typically used to handle duplicate spilled
inlined functions12 and virtual function dispatch tables.13 If this mechanism is
not available, the alternative is usually to emit these items with internal linkage,
at the expense of generating larger code. The requirement that an inline function
have a single address makes it difficult to implement that alternative in a
standard-conforming way.

14.4.2 Queried Instantiation
In the mid-1990s, a company called Sun Microsystems14 released a
reimplementation of its C++ compiler (version 4.0) with a new and interesting
solution of the instantiation problem, which we call queried instantiation.
Queried instantiation is conceptually remarkably simple and elegant, and yet it is
chronologically the most recent class of instantiation schemes that we review
here. In this scheme, a database shared by the compilations of all translation
units participating in a program is maintained. This database keeps track of
which specializations have been instantiated and on what source code they
depend. The generated specializations themselves are typically stored with this
information in the database. Whenever a point of instantiation for a linkable
entity is encountered, one of three things can happen: 1. No specialization is
available: In this case, instantiation occurs, and the resulting specialization is
entered in the database.
2. A specialization is available but is out of date because source changes have
occurred since it was generated. Here, too, instantiation occurs, but the
resulting specialization replaces the one previously stored in the database.
3. An up-to-date specialization is available in the database. Nothing needs to be
done. Although conceptually simple, this design presents a few
implementation challenges: • It is not trivial to maintain correctly the
dependencies of the database contents with respect to the state of the source
code. Although it is not incorrect to mistake the third case for the second,
doing so increases the amount of work done by the compiler (and hence
overall build time).
• It is quite common to compile multiple source files concurrently. Hence, an
industrial-strength implementation needs to provide the appropriate amount of
concurrency control in the database.
Despite these challenges, the scheme can be implemented quite efficiently.
Furthermore, there are no obvious pathological cases that would make this
solution scale poorly, in contrast, for example, with greedy instantiation, which
may lead to a lot of wasted work.
The use of a database may also present some problems to the programmer,
unfortunately. The origin of most of these problems lies in that fact that the
traditional compilation model inherited from most C compilers no longer
applies: A single translation unit no longer produces a single standalone object
file. Assume, for example, that you wish to link your final program. This link
operation needs not only the contents of each of the object files associated with

your various translation units, but also the object files stored in the database.
Similarly, if you create a binary library, you need to ensure that the tool that
creates that library (typically a linker or an archiver) is aware of the database
contents. More generally, any tool that operates on object files may need to be
made aware of the contents of the database. Many of these problems can be
alleviated by not storing the instantiations in the database, but instead by
emitting the object code in the object file that caused the instantiation in the first
place.
Libraries present yet another challenge. A number of generated specializations
may be packaged in a library. When the library is added to another project, that
project’s database may need to be made aware of the instantiations that are
already available. If not, and if the project creates some of its own points of
instantiation for the specializations present in the library, duplicate instantiation
may occur. A possible strategy to deal with such situations is to use the same
linker technology that enables greedy instantiation: Make the linker aware of
generated specializations and have it weed out duplicates (which should
nonetheless occur much less frequently than with greedy instantiation). Various
other subtle arrangements of sources, object files, and libraries can lead to
frustrating problems such as missing instantiations because the object code
containing the required instantiation was not linked in the final executable
program.
Ultimately, queried instantiation did not survive in the marketplace, and even
Sun’s compiler now uses greedy instantiation.

14.4.3 Iterated Instantiation
The first compiler to support C++ templates was Cfront 3.0—a direct descendant
of the compiler that Bjarne Stroustrup wrote to develop the language.15 An
inflexible constraint on Cfront was that it had to be very portable from platform
to platform, and this meant that it (1) used the C language as a common target
representation across all target platforms and (2) used the local target linker. In
particular, this implied that the linker was not aware of templates. In fact, Cfront
emitted template instantiations as ordinary C functions, and therefore it had to
avoid duplicate instantiations. Although the Cfront source model was different
from the standard inclusion model, its instantiation strategy can be adapted to fit
the inclusion model. As such, it also merits recognition as the first incarnation of
iterated instantiation. The Cfront iteration can be described as follows: 1.

Compile the sources without instantiating any required linkable specializations.
2. Link the object files using a prelinker.
3. The prelinker invokes the linker and parses its error messages to determine
whether any are the result of missing instantiations. If so, the prelinker
invokes the compiler on sources that contain the needed template definitions,
with options to generate the missing instantiations.
4. Repeat step 3 if any definitions are generated.
The need to iterate step 3 is prompted by the observation that the instantiation of
one linkable entity may lead to the need for another such entity that was not yet
instantiated. Eventually the iteration will “converge,” and the linker will succeed
in building a complete program.
The drawbacks of the original Cfront scheme are quite severe: • The perceived
time to link is augmented not only by the prelinker overhead but also by the cost
of every required recompilation and relinking. Some users of Cfront-based
systems reported link times of “a few days” compared with “about an hour” with
the alternative schemes reported earlier.
• Diagnostics (errors, warnings) are delayed until link time. This is especially
painful when linking becomes expensive and the developer must wait hours
just to find out about a typo in a template definition.
• Special care must be taken to remember where the source containing a
particular definition is located (step 1). Cfront in particular used a central
repository, which had to deal with some of the challenges of the central
database in the queried instantiation approach. In particular, the original Cfront
implementation was not engineered to support concurrent compilations.
The iteration principle was subsequently refined both by the Edison Design
Group’s (EDG) implementation and by HP’s aC++,16 eliminating some of the
drawbacks of the original Cfront implementation. In practice, these
implementations work quite well, and, although a build “from scratch” is
typically more time consuming than the alternative schemes, subsequent build
times are quite competitive. Still, relatively few C++ compilers use iterated
instantiation anymore.

14.5 Explicit Instantiation
It is possible to create explicitly a point of instantiation for a template
specialization. The construct that achieves this is called an explicit instantiation
directive. Syntactically, it consists of the keyword template followed by a

declaration of the specialization to be instantiated. For example: Click here to
view code image
template
void f(T)
{
}
// four valid explicit instantiations:
template void f(int);
template void f<>(float);
template void f(long);
template void f(char); Note that every instantiation directive is
valid. Template arguments can be deduced (see Chapter 15).

Members of class templates can also be explicitly instantiated in this way:
Click here to view code image
template
class S {
public:
void f() {
}
};
template void S::f();
template class S; Furthermore, all the members of a class
template specialization can be explicitly instantiated by explicitly
instantiating the class template specialization. Because these
explicit instantiation directives ensure that a definition of the
named template specialization (or member thereof) is created, the
explicit instantiation directives above are more accurately referred
to as explicit instantiation definitions. A template specialization
that is explicitly instantiated should not be explicitly specialized,
and vice versa, because that would imply that the two definitions
could be different (thus violating the ODR).

14.5.1 Manual Instantiation
Many C++ programmers have observed that automatic template instantiation has
a nontrivial negative impact on build times. This is particularly true with
compilers that implement greedy instantiation (Section 14.4.1 on page 256),
because the same template specializations may be instantiated and optimized in
many different translation units.
A technique to improve build times consists in manually instantiating those
template specializations that the program requires in a single location and

inhibiting the instantiation in all other translation units. One portable way to
ensure this inhibition is to not provide the template definition except in the
translation unit where it is explicitly instantiated.17 For example: Click here to
view code image
// ===== translation unit 1:
template void f(); // no definition: prevents
instantiation
// in this translation unit
void g()
{
f();
}
// ===== translation unit 2:
template void f()
{
// implementation
}
template void f(); // manual instantiation
void g();
int main()
{
g();
}

In the first translation unit, the compiler cannot see the definition of the function
template f, so it will not (cannot) produce an instantiation of f. The
second translation unit provides the definition of f via an explicit
instantiation definition; without it, the program would fail to link.
Manual instantiation has a clear disadvantage: We must carefully keep track of
which entities to instantiate. For large projects this quickly becomes an excessive
burden; hence we do not recommend it. We have worked on several projects that
initially underestimated this burden, and we came to regret our decision as the
code matured.
However, manual instantiation also has a few advantages because the
instantiation can be tuned to the needs of the program. Clearly, the overhead of
large headers is avoided, as is the overhead of repeatedly instantiating the same
templates with the same arguments in multiple translation units. Moreover, the
source code of template definition can be kept hidden, but then no additional
instantiations can be created by a client program.
Some of the burden of manual instantiation can be alleviated by placing the

template definition into a third source file, conventionally with the extension
.tpp. For our function f, this breaks down into: Click here to view code image
// ===== f.hpp:
template void f(); // no definition: prevents
instantiation
// ===== t.hpp:
#include "f.hpp"
template void f() //definition
{
// implementation
}
// ===== f.cpp:
#include "f.tpp"
template void f(); // manual instantiation

This structure provides some flexibility. One can include only f.hpp to get the
declaration of f, with no automatic instantiation. Explicit instantiations can be
manually added to f.cpp as needed. Or, if manual instantiations become too
onerous, one can also include f.tpp to enable automatic instantiation.

14.5.2 Explicit Instantiation Declarations
A more targeted approach to the elimination of redundant automatic
instantiations is the use of an explicit instantiation declaration, which is an
explicit instantiation directive prefixed by the keyword extern. An explicit
instantiation declaration generally suppresses automatic instantiation of the
named template specialization, because it declares that the named template
specialization will be defined somewhere in the program (by an explicit
instantiation definition). We say generally, because there are many exceptions to
this: • Inline functions can still be instantiated for the purpose of expanding them
inline (but no separate object code is generated).
• Variables with deduced auto or decltype(auto) types and functions with
deduced return types can still be instantiated to determine their types.
• Variables whose values are usable as constant-expressions can still be
instantiated so their values can be evaluated.
• Variables of reference types can still be instantiated so the entity they reference
can be resolved.
• Class templates and alias templates can still be instantiated to check the

resulting types.
Using explicit instantiation declarations, we can provide the template definition
for f in the header (t.hpp), then suppress automatic instantiation for
commonly used specializations, as follows: Click here to view code image
// ===== t.hpp:
template void f()
{
}
extern template void f(); // declared but not defined
extern template void f(); // declared but not defined
// ===== t.cpp:
template void f(); // definition
template void f(); // definition

Each explicit instantiation declaration must be paired with a corresponding
explicit instantiation definition, which must follow the explicit instantiation
declaration. Omitting the definition will result in a linker error.
Explicit instantiation declarations can be used to improve compile or link
times when certain specializations are used in many different translation units.
Unlike with manual instantiation, which requires manually updating the list of
explicit instantiation definitions each time a new specialization is required,
explicit instantiation declarations can be introduced as an optimization at any
point. However, the compile-time benefits may not be as significant as with
manual instantiation, both because some redundant automatic instantiation is
likely to occur18 and because the template definitions are still parsed as part of
the header.

14.6 Compile-Time if Statements
As introduced in Section 8.5 on page 134, C++17 added a new statement kind
that turns out to be remarkably useful when writing templates: compile-time if.
It also introduces a new wrinkle in the instantiation process.
The following example illustrates its basic operation: Click here to view code
image
template bool f(T p) {
if constexpr (sizeof(T) <= sizeof(long long)) {
return p>0;
} else {
return p.compare(0) > 0;

}
}
bool g(int n) {
return f(n); // OK
}

The compile-time if is an if statement, where the if keyword is immediately
followed by the constexpr keyword (as in this example).19 The parenthesized
condition that follows must have a constant Boolean value (implicit conversions
to bool are included in that consideration). The compiler therefore knows
which branch will be selected; the other branch is called the discarded branch.
Of particular interest is that during the instantiation of templates (including
generic lambdas), the discarded branch is not instantiated. That is necessary for
our example to be valid: We are instantiating f(T) with T = int, which
means that the else branch is discarded. If it weren’t discarded, it would be
instantiated and we’d run into an error for the expression p.compare(0)
(which isn’t valid when p is a simple integer).
Prior to C++17 and its constexpr if statements, avoiding such errors required
explicit template specialization or overloading (see Chapter 16) to achieve
similar effects.
The example above, in C++14, might be implemented as follows: Click here
to view code image
template struct Dispatch { //only to be instantiated when b
is false
static bool f(T p) { //(due to next specialization for true)
return p.compare(0) > 0;
}
};
template<> struct Dispatch {
static bool f(T p) {
return p > 0;
}
};
template bool f(T p) {
return Dispatch::f(p);
}
bool g(int n) {
return f(n); // OK
}

Clearly, the constexpr if alternative expresses our intention far more clearly and
concisely. However, it requires implementations to refine the unit of

instantiation: Whereas previously function definitions were always instantiated
as a whole, now it must be possible to inhibit the instantiation of parts of them.
Another very handy use of constexpr if is expressing the recursion needed to
handle function parameter packs. To generalize the example, introduced in
Section 8.5 on page 134: Click here to view code image
template
void f(Head&& h, Remainder&&… r) {
doSomething(std::forward(h));
if constexpr (sizeof…(r) != 0) {
// handle the remainder recursively (perfectly forwarding the
arguments):
f(std::forward(r)…);
}
}

Without constexpr if statements, this requires an additional overload of the f()
template to ensure that recursion terminates.
Even in nontemplate contexts, constexpr if statements have a somewhat
unique effect: Click here to view code image
void h();
void g() {
if constexpr (sizeof(int) == 1) {
h();
}
}

On most platforms, the condition in g() is false and the call to h() is
therefore discarded. As a consequence, h() need not necessarily be defined at
all (unless it is used elsewhere, of course). Had the keyword constexpr been
omitted in this example, a lack of a definition for h() would often elicit an error
at link time.20

14.7 In the Standard Library
The C++ standard library includes a number of templates that are only
commonly used with a few basic types. For example, the
std::basic_string class template is most commonly used with char
(because std::string is a type alias of std::basic_string)
or wchar_t, although it is possible to instantiate it with other character-like
types. Therefore, it is common for standard library implementations to introduce
explicit instantiation declarations for these common cases. For example: Click

here to view code image
namespace std {
template,
typename Allocator = allocator>
class basic_string {
…
};
extern template class basic_string;
extern template class basic_string;
}

The source files implementing the standard library will then contain the
corresponding explicit instantiation definitions, so that these common
implementations can be shared among all users of the standard library. Similar
explicit instantiations often exist for the various stream classes, such as
basic_iostream, basic_istream, and so on.

14.8 Afternotes
This chapter deals with two related but different issues: the C++ template
compilation model and various C++ template instantiation mechanisms.
The compilation model determines the meaning of a template at various stages
of the translation of a program. In particular, it determines what the various
constructs in a template mean when it is instantiated. Name lookup is an
essential ingredient of the compilation model.
Standard C++ only supports a single compilation model, the inclusion model.
However, the 1998 and 2003 standards also supported a separation model of
template compilation, which allowed a template definition to be written in a
different translation unit from its instantiations. These exported templates were
only ever implemented once, by the Edison Design Group (EDG).21 Their
implementation effort determined that (1) implementing the separation model of
C++ templates was vastly more difficult and time consuming than had been
anticipated, and (2) the presumed benefits of the separation model, such as
improved compile times, did not materialize due to complexities of the model.
As the development of the 2011 standard was wrapping up, it became clear that
other implementers were not going to support the feature, and the C++ standards
committee voted to remove exported templates from the language. We refer
readers interested in the details of the separation model to the first edition of this
book ([VandevoordeJosuttisTemplates1st]), which describes the behavior of
exported templates.

The instantiation mechanisms are the external mechanisms that allow C++
implementations to create instantiations correctly. These mechanisms may be
constrained by requirements of the linker and other software building tools.
While instantiation mechanisms differ from one implementation to the next (and
each has its trade-offs), they generally do not have a significant impact on dayto-day programming in C++.
Shortly after C++11 was completed, Walter Bright, Herb Sutter, and Andrei
Alexandrescu proposed a “static if” feature not unlike constexpr if (via paper
N3329). It was, however, a more general feature that could appear even outside
of function definitions. (Walter Bright is the principal designer and implementer
of the D programming language, which has a similar feature.) For example:
Click here to view code image
template
struct Fact {
static if (N <= 1) {
constexpr unsigned long value = 1;
} else {
constexpr unsigned long value = N*Fact::value;
}
};

Note how class-scope declarations are made conditional in this example. This
powerful ability was controversial, however, with some committee members
fearing that it might be abused and others not liking some technical aspects of
the proposal (such as the fact that no scope is introduced by the braces and the
discarded branch is not parsed at all).
A few years later, Ville Voutilainen came back with a proposal (P0128) that
was mostly what would become constexpr if statements. It went through a few
minor design iterations (involving tentative keywords static_if and
constexpr_if) and, with the help of Jens Maurer, Ville eventually
shepherded the proposal into the language (via paper P0292r2).
1 The term instantiation is sometimes also used to refer to the creation of
objects from types. In this book, however, it always refers to template
instantiation.
2 The term specialization is used in the general sense of an entity that is a
specific instance of a template (see Chapter 10). It does not refer to the
explicit specialization mechanism described in Chapter 16.
3 Anonymous unions are always special in this way: Their members can be
considered to be members of the enclosing class. An anonymous union is
primarily a construct that says that some class members share the same

storage.
Some compilers, such as GCC, allow zero-length arrays as extensions and
may therefore accept this code even when N ends up being 0.
5 Typical examples are smart pointer templates (e.g., the standard
std::unique_ptr).
6 Besides two-phase lookup, terms such as two-stage lookup or two-phase name
lookup are also used.
7 Surprisingly, this is not clearly specified in the standard at the time of this
writing. However, it is not expected to be a controversial issue.
8 The call operator of generic lambdas are a subtle exception to that
observation.
9 In modern compilers the inlining of calls is typically handled by a mostly
language-independent component of the compiler dedicated to optimizations
(a “back end” or “middle end”). However, C++ “front ends” (the C++-specific
part of the C++ compiler) that were designed in the earlier days of C++ may
also have the ability to expand calls inline because older back ends were too
conservative when considering calls for inline expansion.
10 The original C++98 standard also provided a separation model. It never gained
popularity and was removed just before publishing the C++11 standard.
11 Current systems have grown to detect certain other differences, however. For
example, they might report if one instantiation has associated debugging
information and another does not.
12 When a compiler is unable to “inline” every call to a function that you marked
with the keyword inline, a separate copy of the function is emitted in the
object file. This may happen in multiple object files.
13 Virtual function calls are usually implemented as indirect calls through a table
of pointers to functions. See [LippmanObjMod] for a thorough study of such
implementation aspects of C++.
14 Sun Microsystems was later acquired by Oracle.
15 Do not let this phrase mislead you into thinking that Cfront was an academic
prototype: It was used in industrial contexts and formed the basis of many
commercial C++ compiler offerings. Release 3.0 appeared in 1991 but was
plagued with bugs. Version 3.0.1 followed soon thereafter and made templates
usable.
16 HP’s aC++ was grown out of technology from a company called Taligent (later
absorbed by International Business Machines, or IBM). HP also added greedy
instantiation to aC++ and made that the default mechanism.
4

17

In the 1998 and 2003 C++ standards, this was the only portable way to inhibit
instantiation in other translation units.
18 An interesting part of this optimization problem is to determine exactly which
specializations are good candidates for explicit instantiation declarations. Lowlevel utilities such as the common Unix tool nm can be useful in identifying
which automatic instantiations actually made it into the object files that
comprise a program.
19 Although the code reads if constexpr, the feature is called constexpr if,
because it is the “constexpr” form of if.
20 Optimization may nonetheless mask the error. With constexpr if the problem is
guaranteed not to exist.
21 Ironically, EDG was the most vocal opponent of the feature when it was added
to the working paper for the original standard.

Chapter 15
Template Argument Deduction
Explicitly specifying template arguments on every call to a function template
(e.g., concat(s, 3)) can quickly lead to unwieldy
code. Fortunately, a C++ compiler can often automatically determine the
intended template arguments using a powerful process called template argument
deduction.
In this chapter we explain the details of the template argument deduction
process. As is often the case in C++, there are many rules that usually produce
an intuitive result. A solid understanding of this chapter allows us to avoid the
more surprising situations.
Although template argument deduction was first developed to ease the
invocation of function templates, it has since been broadened to apply to several
other uses, including determining the types of variables from their initializers.

15.1 The Deduction Process
The basic deduction process compares the types of an argument of a function
call with the corresponding parameterized type of a function template and
attempts to conclude the correct substitution for one or more of the deduced
parameters. Each argument-parameter pair is analyzed independently, and if the
conclusions differ in the end, the deduction process fails. Consider the following
example: Click here to view code image
template
T max (T a, T b)
{
return b < a ? a : b;
}
auto g = max(1, 1.0); Here the first call argument is of type int, so
the parameter T of our original max() template is tentatively deduced
to be int. The second call argument is a double, however, and so T
should be double for this argument: This conflicts with the previous
conclusion. Note that we say that “the deduction process fails,” not

that “the program is invalid.” After all, it is possible that the
deduction process would succeed for another template named max
(function templates can be overloaded much like ordinary functions;
see Section 1.5 on page 15 and Chapter 16).

If all the deduced template parameters are consistently determined, the
deduction process can still fail if substituting the arguments in the rest of the
function declaration results in an invalid construct. For example: Click here to
view code image
template< typename T>
typename T::ElementT at (T a, int i)
{
return a[i];
}
void f (int* p)
{
int x = at(p, 7);
}

Here T is concluded to be int* (there is only one parameter type where T
appears, so there are obviously no analysis conflicts). However, substituting
int* for T in the return type T::ElementT is clearly invalid C++, and the
deduction process fails.1
We still need to explore how argument-parameter matching proceeds. We
describe it in terms of matching a type A (derived from the call argument type) to
a parameterized type P (derived from the call parameter declaration). If the call
parameter is declared with a reference declarator, P is taken to be the type
referenced, and A is the type of the argument. Otherwise, however, P is the
declared parameter type, and A is obtained from the type of the argument by
decaying2 array and function types to pointer types, ignoring top-level const
and volatile qualifiers. For example: Click here to view code image
template void f(T); // parameterized type P is T
template void g(T&); // parameterized type P is also T
double arr[20];
int const seven = 7;
f(arr); // nonreference parameter: T is double*
g(arr); // reference parameter: T is double[20]
f(seven); // nonreference parameter: T is int
g(seven); // reference parameter: T is int const
f(7); // nonreference parameter: T is int
g(7); // reference parameter: T is int => ERROR: can’t pass 7 to int&

For a call f(arr), the array type of arr decays to type double*, which is

the type deduced for T. In f(seven) the const qualification is stripped and
hence T is deduced to be int. In contrast, calling g(x) deduces T to be type
double[20] (no decay occurs). Similarly, g(seven) has an lvalue argument
of type int const, and because const and volatile qualifiers are not
dropped when matching reference parameters, T is deduced to be int const.
However, note that g(7) would deduce T to be int (because nonclass rvalue
expressions never have const or volatile qualified types), and the call
would fail because an argument 7 cannot be passed to a parameter of type int&.
The fact that no decay occurs for arguments bound to reference parameters
can be surprising when the arguments are string literals. Reconsider our max()
template declared with references: Click here to view code image
template
T const& max(T const& a, T const& b); It would be reasonable to
expect that for the expression max("Apple", "Pie") T is deduced to be
char const*. However, the type of "Apple" is char const[6], and the
type of "Pie" is char const[4]. No array-to-pointer decay occurs
(because the deduction involves reference parameters), and therefore
T would have to be both char[6] and char[4] for deduction to succeed.
That is, of course, impossible. See Section 7.4 on page 115 for a
discussion about how to deal with this situation.

15.2 Deduced Contexts
Parameterized types that are considerably more complex than just “T” can be
matched to a given argument type. Here are a few examples that are still fairly
basic: Click here to view code image
template
void f1(T*);
template
void f2(E(&)[N]);
template
void f3(T1 (T2::*)(T3*));
class S {
public:
void f(double*);
};
void g (int*** ppp)

{
bool b[42];
f1(ppp); // deduces T to be int**
f2(b); // deduces E to be bool and N to be 42
f3(&S::f); // deduces T1 = void, T2 = S, and T3 = double}

Complex type declarations are built from more elementary constructs (pointer,
reference, array, and function declarators; pointer-to-member declarators;
template-ids; and so forth), and the matching process proceeds from the top-level
construct and recurses through the composing elements. It is fair to say that most
type declaration constructs can be matched in this way, and these are called
deduced contexts. However, a few constructs are not deduced contexts. For
example: • Qualified type names. For example, a type name like Q::X will
never be used to deduce a template parameter T.
• Nontype expressions that are not just a nontype parameter. For example, a type
name like S will never be used to deduce I. Neither will T be deduced
by matching against a parameter of type int(&)[sizeof(S)]. These
limitations should come as no surprise because the deduction would, in
general, not be unique (or even finite), although this limitation of qualified
type names is sometimes easily overlooked. A nondeduced context does not
automatically imply that the program is in error or even that the parameter
being analyzed cannot participate in type deduction. To illustrate this, consider
the following, more intricate example: Click here to view code image
details/fppm.cpp
template
class X {
public:
using I = int;
void f(int) {
}
};
template
void fppm(void (X::*p)(typename X::I));;
int main()
{
fppm(&X<33>::f); // fine: N deduced to be 33
}

In the function template fppm(), the subconstruct X::I is a nondeduced
context. However, the member-class component X of the pointer-to-member
type is a deducible context, and when the parameter N, which is deduced from it,

is plugged in the nondeduced context, a type compatible with that of the actual
argument &X<33>::f is obtained. The deduction therefore succeeds on that
argument-parameter pair.
Conversely, it is possible to deduce contradictions for a parameter type
entirely built from deduced contexts. For example, assuming suitably declared
class templates X and Y: Click here to view code image
template
void f(X, Y>);
void g()
{
f(X, Y>()); // OK
f(X, Y>()); // ERROR: deduction fails
}

The problem with the second call to the function template f() is that the two
arguments deduce different arguments for the parameter T, which is not valid.
(In both cases, the function call argument is a temporary object obtained by
calling the default constructor of the class template X.)

15.3 Special Deduction Situations
There are several situations in which the pair (A, P) used for deduction is not
obtained from the arguments to a function call and the parameters of a function
template. The first situation occurs when the address of a function template is
taken. In this case, P is the parameterized type of the function template
declaration, and A is the function type underlying the pointer that is initialized or
assigned to. For example: Click here to view code image
template
void f(T, T);
void (*pf)(char, char) = &f; In this example, P is void(T, T) and A
is void(char, char). Deduction succeeds with T substituted with char,
and pf is initialized to the address of the specialization f.

Similarly, function types are used for P and A for a few other special
situations: • Determining a partial ordering between overloaded function
templates • Matching an explicit specialization to a function template • Matching
an explicit instantiation to a template
• Matching a friend function template specialization to a template • Matching a
placement operator delete or operator delete[] to a

corresponding placement operator new or operator new[] template
Some of these topics, along with the use of template argument deduction for
class template partial specializations, are further developed in Chapter 16.
Another special situation occurs with conversion function templates. For
example: Click here to view code image
class S {
public:
template operator T&();
};

In this case, the pair (P, A) is obtained as if it involved an argument of the type
to which we are attempting to convert and a parameter type that is the return
type of the conversion function. The following code illustrates one variation:
void f(int (&)[20]);
void g(S s)
{
f(s);
}
Here we are attempting to convert S to int (&)[20]. Type A is therefore
int[20] and type P is T. The deduction succeeds with T substituted with
int[20].
Finally, some special treatment is also needed for the deduction of the auto
placeholder type. That is discussed in Section 15.10.4 on page 303.

15.4 Initializer Lists
When the argument of a function call is an initializer list, that argument doesn’t
have a specific type, so in general no deduction will be performed from that
given pair (A, P) because there is no A. For example: Click here to view code
image
#include 
template void f(T p);
int main() {
f({1, 2, 3}); // ERROR: cannot deduce T from a braced list
}

However, if the parameter type P, after removing references and top-level

const and volatile qualifiers, is equivalent to
std::initializer_list for some type P′ that has a deducible
pattern, deduction proceeds by comparing P′ to the type of each element in the
initializer list, succeeding only if all of the elements have the same type: Click
here to view code image
deduce/initlist.cpp
#include 
template void f(std::initializer_list);
int main()
{
f({2, 3, 5, 7, 9}); // OK: T is deduced to int
f({’a’, ’e’, ’i’, ’o’, ’u’, 42}); //ERROR: T deduced to both char and
int
}

Similarly, if the parameter type P is a reference to an array type with element
type P′ for some type P′ that has a deducible pattern, deduction proceeds by
comparing P′ to the type of each element in the initializer list, succeeding only if
all of the elements have the same type. Furthermore, if the bound has a deducible
pattern (i.e., just names a nontype template parameter), then that bound is
deduced to the number of elements in the list.

15.5 Parameter Packs
The deduction process matches each argument to each parameter to determine
the values of template arguments. When performing template argument
deduction for variadic templates, however, the 1:1 relationship between
parameters and arguments no longer holds, because a parameter pack can match
multiple arguments. In this case, the same parameter pack (P) is matched to
multiple arguments (A), and each matching produces additional values for any
template parameter packs in P: Click here to view code image
template
void f(First first, Rest… rest);
void g(int i, double j, int* k)
{
f(i, j, k); // deduces First to int, Rest to {double, int*}

}

Here, the deduction for the first function parameter is simple, since it does not
involve any parameter packs. The second function parameter, rest, is a
function parameter pack. Its type is a pack expansion (Rest…) whose pattern is
the type Rest: This pattern serves as P, to be compared against the types A of
the second and third call arguments. When compared against the first such A (the
type double), the first value in the template parameter pack Rest is deduced
to double. Similarly, when compared against the second such A (the type
int*), the second value in the template parameter pack Rest is deduced to
int*. Thus, deduction determines the value of the parameter pack Rest to be
the sequence {double, int*}. Substituting the results of that deduction and
the deduction for the first function parameter yields the function type
void(int, double, int*), which matches the argument types at the call
site.
Because deduction for function parameter packs uses the pattern of the
expansion for its comparison, the pattern can be arbitrarily complex, and values
for multiple template parameters and parameter packs can be determined from
each of the argument types. Consider the deduction behavior of the functions
h1() and h2(), below: Click here to view code image
template class pair { };
template
void h1(pair const&…);
template
void h2(pair const&…);
void foo(pair pif, pair pid,
pair pdd)
{
h1(pif, pid); // OK: deduces T to int, Rest to {float, double}
h2(pif, pid); // OK: deduces Ts to {int, int}, Rest to {float,
double}
h1(pif, pdd); // ERROR: T deduced to int from the 1st arg, but to
double from the 2nd
h2(pif, pdd); // OK: deduces Ts to {int, double}, Rest to {float,
double}
}

For both h1() and h2(), P is a reference type that is adjusted to the
unqualified version of the reference (pair or pair, respectively) for deduction against each argument type. Since all
parameters and arguments are specializations of class template pair, the
template arguments are compared. For h1(), the first template argument (T) is

not a parameter pack, so its value is deduced independently for each argument. If
the deductions differ, as in the second call to h1(), deduction fails. For the
second pair template argument in both h1() and h2() (Rest), and for the
first pair argument in h2() (Ts), deduction determines successive values for
the template parameter packs from each of the argument types in A.
Deduction for parameter packs is not limited to function parameter packs
where the argument-parameter pairs come from call arguments. In fact, this
deduction is used wherever a pack expansion is at the end of a function
parameter list or a template argument list.3 For example, consider two similar
operations on a simple Tuple type: Click here to view code image
template class Tuple { };
template
bool f1(Tuple, Tuple);
template
bool f2(Tuple, Tuple);
void bar(Tuple sv,
Tuple uv)
{
f1(sv, sv); // OK: Types is deduced to {short, int, long}
f2(sv, sv); // OK: Types1 is deduced to {short, int, long},
// Types2 is deduced to {short, int, long}
f1(sv, uv); // ERROR: Types is deduced to {short, int, long} from the
1st arg, but
// to {unsigned short, unsigned, unsigned long} from the 2nd
f2(sv, uv); // OK: Types1 is deduced to {short, int, long},
// Types2 is deduced to {unsigned short, unsigned, unsigned long}
}

In both f1() and f2(), the template parameter packs are deduced by
comparing the pattern of the pack expansion embedded within the Tuple type
(e.g., Types for h1()) against each of the template arguments of the Tuple
type provided by the call argument, deducing successive values for the
corresponding template parameter pack. The function f1() uses the same
template parameter pack Types in both function parameters, ensuring that
deduction only succeeds when the two function call arguments have the same
Tuple specialization as their type. The function f2(), on the other hand, uses
different parameter packs for the Tuple types in each of its function
parameters, so the types of the function call arguments can be different—so long
as both are specializations of Tuple.

15.5.1 Literal Operator Templates
Literal operator templates have their argument determined in a unique way. The
following example illustrates this: Click here to view code image
template int operator "" _B7(); // #1
…
int a = 121_B7; // #2

Here, the initializer for #2 contains a user-defined literal, which is turned into a
call to the literal operator template #2 with the template argument list <’1’,
’2’, ’1’>. Thus, an implementation of the literal operator such as Click here
to view code image
template
int operator"" _B7()
{
std::array chars{cs…}; //initialize array of passed
chars
for (char c : chars) { //and use it (print it here)
std::cout << "’" << c << "’";
}
std::cout << ’\n’;
return …;
}

will output ’1’ ’2’ ’1’ ’.’ ’5’ for 121.5_B7.
Note that this technique is only supported for numeric literals that are valid
even without the suffix. For example: Click here to view code image
auto
auto
auto
auto
auto

b
c
d
e
f

=
=
=
=
=

01.3_B7; // OK: deduces <’0’, ’1’, ’.’, ’3’>
0xFF00_B7; // OK: deduces <’0’, ’x’, ’F’, ’F’, ’0’, ’0’>
0815_B7; // ERROR: 8 is no valid octal literal
hello_B7; // ERROR: identifier hello_B7 is not defined
"hello"_B7; //ERROR: literal operator _B7 does not match

See Section 25.6 on page 599 for an application of the feature to compute
integral literals at compile time.

15.6 Rvalue References
C++11 introduced rvalue references to enable new techniques, including move
semantics and perfect forwarding. This section describes the interactions
between rvalue references and deduction.

15.6.1 Reference Collapsing Rules
Programmers are not allowed to directly declare a “reference to a reference”:
Click here to view code image
int const& r = 42;
int const& & ref2ref = i; // ERROR: reference to reference is invalid

However, when composing types through the substitution of template
parameters, type aliases, or decltype constructs, such situations are permitted.
For example: Click here to view code image
using RI = int&;
int i = 42;
RI r = i;
R const& rr = r; // OK: rr has type int&

The rules that determine the type resulting from such a composition are known
as the reference collapsing rules.4 First, any const or volatile qualifiers
applied on top of the inner reference are simply discarded (i.e., only the
qualifiers under the inner reference are retained). Then the two references are
reduced to a single reference according to Table 15.1, which can be summarized
as “if either reference is an lvalue reference, so is the resulting type; otherwise, it
is an rvalue reference.”
Inner reference Outer reference Resulting reference
&
+ &
→ &
&
+ &&
→ &
&&
+ &
→ &
&&
+ &&
→ &&
Table 15.1. Reference Collapsing Rules
One more example shows these rules in action:
Click here to view code image
using RCI = int const&;
RCI volatile&& r = 42; // OK: r has type int const&
using RRI = int&&;
RRI const&& rr = 42; // OK: rr has type int&&

Here volatile is applied on top of the reference type RCI (an alias for int
const&) and is therefore discarded. An rvalue reference is then placed on top
of that type, but since the underlying type is an lvalue reference and lvalue

references “take precedence” in the reference collapsing rule, the overall type
remains int const& (or RCI, which is an equivalent alias). Similarly, the
const on top of RRI is discarded, and applying an rvalue reference on top of
the resulting rvalue reference type, still leaves us with an rvalue reference type in
the end (which is able to bind an rvalue like 42).

15.6.2 Forwarding References
As introduced in Section 6.1 on page 91, template argument deduction behaves
in a special way when a function parameter is a forwarding reference (an rvalue
reference to a template parameter of that function template). In this case,
template argument deduction considers not just the type of the function call
argument but also whether that argument is an lvalue or an rvalue. In the cases
where the argument is an lvalue, the type determined by template argument
deduction is an lvalue reference to the argument type, and the reference
collapsing rules (see above) ensure that the substituted parameter will be an
lvalue reference. Otherwise, the type deduced for the template parameter is
simply the argument type (not a reference type), and the substituted parameter is
an rvalue reference to that type. For example: Click here to view code image
template void f(T&& p); // p is a forwarding reference
void g()
{
int i;
int const j = 0;
f(i); // argument
// parameter phas
f(j); // argument
// parameter phas
f(2); // argument
// parameter phas
}

is an lvalue; deduces Tto int&and
type int&
is an lvalue; deduces Tto int const&
type int const&
is an rvalue; deduces Tto int
type int&&

In the call f(i) the template parameter T is deduced to int&, since the
expression i is an lvalue of type int. Substituting int& for T into the
parameter type T&& requires reference collapsing, and we apply the rule & + &&
! & to conclude that the resulting parameter type is int&, which is perfectly
suited to accept an lvalue of type int. In contrast, in the call f(2), the
argument 2 is an rvalue and the template parameter is therefore deduced to
simply be the type of that rvalue (i.e., int). No reference collapsing is needed

for the resulting function parameter, which is just int&& (again, a parameter
suited for its argument).
The deduction of T as a reference type can have some interesting effects on
the instantiation of the template. For example, a local variable declared with type
T will, after instantiation for an lvalue, have reference type and will therefore
require an initializer: Click here to view code image
template void f(T&&) // p is a forwarding reference
{
T x; // for passed lvalues, x is a reference
…
}

This means that the definition of the function f() above needs to be careful
how it uses the type T, or the function template itself won’t work properly with
lvalue arguments. To deal with this situation, the std::remove_reference
type trait is frequently used to ensure that x is not a reference: Click here to view
code image
template void f(T&&) // p is a forwarding reference
{
std::remove_reference_t x; // x is never a reference
…
}

15.6.3 Perfect Forwarding
The combination of the special deduction rule for rvalue references and the
reference collapsing rules makes it possible to write a function template with a
parameter that accepts almost any argument5 and captures its salient properties
(its type and whether it is an lvalue or an rvalue). The function template can then
“forward” the argument along to another function as follows: Click here to view
code image
class C {
…
};
void g(C&);
void g(C const&);
void g(C&&);
template
void forwardToG(T&& x)
{

g(static_cast(x)); // forward x to g()
}
void foo()
{
C v;
C const c;
forwardToG(v); // eventually calls g(C&)
forwardToG(c); // eventually calls g(C const&)
forwardToG(C()); // eventually calls g(C&&)
forwardToG(std::move(v)); // eventually calls g(C&&)
}

The technique illustrated above is called perfect forwarding, because the result
of calling g() indirectly through forwardToG() will be the same as if the
code called g() directly: No additional copies are made, and the same overload
of g() will be selected.
The use of static_cast within the function forwardToG() requires
some additional explanation. In each instantiation of forwardToG(), the
parameter x will either have lvalue reference type or rvalue reference type.
Regardless, the expression x will be an lvalue of the type that the reference
refers to.6 The static_cast casts x to its original type and lvalue- or rvalueness. The type T&& will either collapse to an lvalue reference (if the original
argument was an lvalue causing T to be an lvalue reference) or will be an rvalue
reference (if the original argument was an rvalue), so the result of the
static_cast has the same type and lvalue- or rvalue-ness as the original
argument, thereby achieving perfect forwarding.
As introduced in Section 6.1 on page 91, the C++ standard library provides a
function template std::forward<>() in header  that should be
used in place of static_cast for perfect forwarding. Using that utility
template better documents the programmer’s intent than the arguably opaque
static_cast constructs shown above and prevents errors such as omitting
one &. That is, the example above is more clearly written as follows: Click here
to view code image
#include 
template void forwardToG(T&& x)
{
g(std::forward(x)); // forward x to g()
}

Perfect Forwarding for Variadic Templates
Perfect forwarding combines well with variadic templates, allowing a function
template to accept any number of function call arguments and forward each of
them along to another function: Click here to view code image
template void forwardToG(Ts&&… xs)
{
g(std::forward(xs)…); // forward all xs to g()
}

The arguments in a call to forwardToG() will (independently) deduce
successive values for the parameter pack Ts (see Section 15.5 on page 275), so
that the types and lvalue- or rvalue-ness of each argument is captured. The pack
expansion (see Section 12.4.1 on page 201) in the call to g() will then forward
each of these arguments using the perfect forwarding technique explained above.
Despite its name, perfect forwarding is not, in fact, “perfect” in the sense that
it does not capture all interesting properties of an expression. For example, it
does not distinguish whether an lvalue is a bit-field lvalue, nor does it capture
whether the expression has a specific constant value. The latter causes problems
particularly when we’re dealing with the null pointer constant, which is a value
of integral type that evaluates to the constant value zero. Since the constant value
of an expression is not captured by perfect forwarding, overload resolution in the
following example will behave differently for the direct call to g() than for the
forwarded call to g(): Click here to view code image
void g(int*);
void g(…);
template void forwardToG(T&& x)
{
g(std::forward(x)); // forward x to g()
}
void foo()
{
g(0); // calls g(int*)
forwardToG(0); // eventually calls g(…)
}

This is yet another reason to use nullptr (introduced in C++11) instead of
null pointer constants: Click here to view code image
g(nullptr); // calls g(int*)
forwardToG(nullptr); // eventually calls g(int*)

All of our examples of perfect forwarding have focused on forwarding the
function arguments while maintaining their precise type and whether it is an
lvalue or rvalue. The same problem occurs when forwarding the return value of a
call to another function, with precisely the same type and value category, a
generalization of lvalues and rvalues discussed in Appendix B. The decltype
facility introduced in C++11 (and described in Section 15.10.2 on page 298)
enables this use of a somewhat verbose idiom: Click here to view code image
template
auto forwardToG(Ts&&… xs) -> decltype(g(std::forward(xs)…))
{
return g(std::forward(xs)…); // forward all xs to g()
}

Note that the expression in the return statement is copied verbatim into the
decltype type, so that the exact type of the return expression is computed.
Moreover, the trailing return type feature is used (i.e., the auto placeholder
before the function name and the -> to indicate the return type) so that the
function parameter pack xs is in scope for the decltype type. This
forwarding function “perfectly” forwards all arguments to g() and then
“perfectly” forwards its result back to the caller.
C++14 introduced additional features to further simplify this case: Click here
to view code image
template
decltype(auto) forwardToG(Ts&&… xs)
{
return g(std::forward(xs)…); // forward all xs to g()
}

The use of decltype(auto) as a return type indicates that the compiler
should deduce the return type from the definition of the function. See Section
15.10.1 on page 296 and Section 15.10.3 on page 301.

15.6.4 Deduction Surprises
The results of the special deduction rule for rvalue references are very useful for
perfect forwarding. However, they can come as a surprise, because function
templates typically generalize the types in the function signature without
affecting what kinds of arguments (lvalue or rvalue) it allows. Consider this
example: Click here to view code image
void int_lvalues(int&); // accepts lvalues of type int

template void lvalues(T&); // accepts lvalues of any type
void int_rvalues(int&&); // accepts rvalues of type int
template void anything(T&&); // SURPRISE: accepts lvalues
and
// rvalues of any type

Programmers who are simply abstracting a concrete function like
int_rvalues to its template equivalent would likely be surprised by the fact
that the function template anything accepts lvalues. Fortunately, this
deduction behavior only applies when the function parameter is written
specifically with the form template-parameter &&, is part of a function template,
and the named template parameter is declared by that function template.
Therefore, this deduction rule does not apply in any of the following situations:
Click here to view code image
template
class X
{
public:
X(X&&); // X is not a template parameter
X(T&&); // this constructor is not a function template
template X(X&&); // X is not a template
parameter template<
typename U> X(U, T&&); // T is a template parameter from
// an outer template
};

Despite the surprising behavior that this template deduction rule gives, the cases
where this behavior causes problems don’t come up all that often in practice.
When it occurs, one can use a combination of SFINAE (see Section 8.4 on page
129 and Section 15.7 on page 284) and type traits such as std::enable_if
(see Section 6.3 on page 98 and Section 20.3 on page 469) to restrict the
template to rvalues: Click here to view code image
template
typename std::enable_if::value>::type
rvalues(T&&); // accepts rvalues of any type

15.7 SFINAE (Substitution Failure Is Not An Error)
The SFINAE (substitution failure is not an error) principle, introduced in Section
8.4 on page 129, is an important aspect of template argument deduction that
prevents unrelated function templates from causing errors during overload

resolution.7
For example, consider a pair of function templates that extracts the beginning
iterator for a container or an array: Click here to view code image
template
T* begin(T (&array)[N])
{
return array;
}
template
typename Container::iterator begin(Container& c)
{
return c.begin();
}
int main()
{
std::vector v;
int a[10];
::begin(v); // OK: only container begin() matches, because the first
deduction fails
::begin(a); // OK: only array begin() matches, because the second
substitution fails
}

The first call to begin(), in which the argument is a std::vector,
attempts template argument deduction for both begin() function templates: •
Template argument deduction for the array begin() fails, because a
std::vector is not an array, so it is ignored.
• Template argument deduction for the container begin() succeeds with
Container deduced to std::vector, so that the function template
is instantiated and called.
The second call to begin(), in which the argument is an array, also partially
fails: • Deduction for the array begin() succeeds with T deduced to int and
N deduced to 10.
• Deduction for the container begin() determines that Container should be
replaced by int[10]. While in general this substitution is fine, the produced
return type Container::iterator is invalid, because an array type does
not have a nested type named iterator. In any other context, trying to
access a nested type that does not exist would cause an immediate compiletime error. During the substitution of template arguments, SFINAE turns such
errors into deduction failures, and the function template is removed from

consideration. Thus, the second begin() candidate is ignored and the
specialization of the first begin() function template is called.

15.7.1 Immediate Context
SFINAE protects against attempts to form invalid types or expressions,
including errors due to ambiguities or access control violations, that occur within
the immediate context of the function template substitution. Defining the
immediate context of a function template substitution is more easily done by
defining what is not in that context.8 Specifically, during function template
substitution for the purpose of deduction, anything that happens during the
instantiation of • the definition of a class template (i.e., its “body” and list of
base classes), • the definition of a function template (“body” and, in the case of a
constructor, its constructor-initializers), • the initializer of a variable template,
• a default argument,
• a default member initializer, or
• an exception specification
is not part of the immediate context of that function template substitution. Any
implicit definition of special member functions triggered by the substitution
process is not part of the immediate context of the substitution either. Everything
else is part of that context.
So if substituting the template parameters of a function template declaration
requires the instantiation of the body of a class template because a member of
that class is being referred to, an error during that instantiation is not in the
immediate context of the function template substitution and is therefore a real
error (even if another function template matches without error). For example:
Click here to view code image
template
class Array {
public:
using iterator = T*;
};
template
void f(Array::iterator first, Array::iterator last);
template
void f(T*, T*);
int main()

{
f(0, 0);// ERROR: substituting int& for T in the first function
template
} // instantiates Array, which then fails

The main difference between this example and the prior example is where the
failure occurs. In the prior example, the failure occurred when forming a type
typename Container::iterator that was in the immediate context of
the substitution of function template begin(). In this example, the failure
occurs in the instantiation of Array, which—although it was triggered
from the function template’s context—actually occurs in the context of the class
template Array. Therefore, the SFINAE principle does not apply, and the
compiler will produce an error.
Here is a C++14 example—relying on deduced return types (see Section
15.10.1 on page 296)— that involves an error during the instantiation of a
function template definition: Click here to view code image
template auto f(T p) {
return p->m;
}
int f(…);
template auto g(T p) -> decltype(f(p));
int main()
{
g(42);
}

The call g(42) deduces T to be int. Making that substitution in the
declaration of g() requires us to determine the type of f(p) (where p is now
known to be of type int) and therefore to determine the return type of f().
There are two candidates for f(). The nontemplate candidate is a match, but not
a very good one because it matches with an ellipsis parameter. Unfortunately, the
template candidate has a deduced return type, and so we must instantiate its
definition to determine that return type. That instantiation fails because p->m is
not valid when p is an int and since the failure is outside the immediate context
of the substitution (because it’s in a subsequent instantiation of a function
definition), the failure produces an error. Because of this, we recommend
avoiding deduced return types if they can easily be specified explicitly.
SFINAE was originally intended to eliminate surprising errors due to
unintended matches with function template overloading, as with the container
begin() example. However, the ability to detect an invalid expression or type

enables remarkable compile-time techniques, allowing one to determine whether
a particular syntax is valid. These techniques are discussed in Section 19.4 on
page 416.
See especially Section 19.4.4 on page 424 for an example of making a type
trait SFINAE-friendly to avoid problems due to the immediate context issue.

15.8 Limitations of Deduction
Template argument deduction is a powerful feature, eliminating the need to
explicitly specify template arguments in most calls to function templates and
enabling both function template overloading (see Section 1.5 on page 15) and
partial class template specialization (see Section 16.4 on page 347). However,
there are a few limitations that programmers may encounter when using
templates and those limitations are discussed in this section.

15.8.1 Allowable Argument Conversions
Normally, template deduction attempts to find a substitution of the function
template parameters that make the parameterized type P identical to type A.
However, when this is not possible, the following differences are tolerable when
P contains a template parameter in a deduced context: • If the original parameter
was declared with a reference declarator, the substituted P type may be more
const/volatile-qualified than the A type.
• If the A type is a pointer or pointer-to-member type, it may be convertible to
the substituted P type by a qualification conversion (in other words, a
conversion that adds const and/or volatile qualifiers).
• Unless deduction occurs for a conversion operator template, the substituted P
type may be a base class type of the A type or a pointer to a base class type of
the class type for which A is a pointer type. For example: Click here to view
code image
template
class B {
};
template
class D : public B {
};

template void f(B*);
void g(D dl)
{
f(&dl); // deduction succeeds with T substituted with long
}

If P does not contain a template parameter in a deduced context, then all implicit
conversion are permissible. For example: Click here to view code image
template int f(T, typename T::X);
struct V {
V();
struct X {
X(double);
};
} v;
int r = f(v, 7.0); // OK: T is deduced to int through the first
parameter,
// which causes the second parameter to have type V::X
// which can be constructed from a double value

The relaxed matching requirements are considered only if an exact match was
not possible. Even so, deduction succeeds only if exactly one substitution was
found to fit the A type to the substituted P type with these added conversions.
Note that these rules are very narrow in scope, ignoring (for example) various
conversions that could be applied to the function arguments to make a call
succeed. For example, consider the following call to the max() function
template shown in Section 15.1 on page 269: Click here to view code image
std::string maxWithHello(std::string s)
{
return ::max(s, "hello");
}

Here, template argument deduction from the first argument deduces T to
std::string, while deduction from the second argument deduces T to
char[6], so template argument deduction fails, because both parameters use
the same template parameter. This failure may come as a surprise, because the
string literal "hello" is implicitly convertible to std::string, and the call
::max(s, "helloa") Click here to view code image
would have succeeded.
Perhaps even more surprising is that when the two arguments have different
class types derived from a common base class, deduction does not consider that

common base class as a candidate for the deduced type. See Section 1.2 on page
7 for a discussion of this issue and possible solutions.

15.8.2 Class Template Arguments
Prior to C++17, template argument deduction applied exclusively to function
and member function templates. In particular, the arguments for a class template
were not deduced from the arguments to a call of one of its constructors. For
example: Click here to view code image
template
class S {
public:
S(T b) : a(b) {
}
private:
T a;
};
S x(12);// ERROR before C++17: the class template parameter T was not
deduced from
// the constructor call argument 12

This limitation is lifted in C++17—see Section 15.12 on page 313.

15.8.3 Default Call Arguments
Default function call arguments can be specified in function templates just as
they are in ordinary functions: Click here to view code image
template
void init (T* loc, T const& val = T())
{
*loc = val;
}

In fact, as this example shows, the default function call argument can depend
on a template parameter. Such a dependent default argument is instantiated only
if no explicit argument is provided—a principle that makes the following
example valid: Click here to view code image
class S {
public:
S(int, int);
};

S s(0, 0);
int main()
{
init(&s, S(7, 42)); // T() is invalid for T = S, but the default
// call argument T() needs no instantiation
// because an explicit argument is given
}

Even when a default call argument is not dependent, it cannot be used to
deduce template arguments. This means that the following is invalid C++: Click
here to view code image
template
void f (T x = 42)
{
}
int main()
{
f(); // OK: T = int
f(); // ERROR: cannot deduce T from default call argument
}

15.8.4 Exception Specifications
Like default call arguments, exception specifications are only instantiated when
they are needed. This means that they do not participate in template argument
deduction. For example: Click here to view code image
template
void f(T, int) noexcept(nonexistent(T()));// #1
template
void f(T, …); // #2 (C-style vararg function)
void test(int i)
{
f(i, i); // ERROR: chooses #1 , but the expression nonexistent(T())
is ill-formed
}

The noexcept specification in the function marked #1 tries to call a
nonexistent function. Normally, such an error directly within the declaration of
the function template would trigger a template argument deduction failure
(SFINAE), allowing the call f(i, i) to succeed by selecting the function

marked #2 that is an otherwise lesser match (matching with an ellipsis parameter
is the worst kind of match from the point of overload resolution; see Appendix
C). However, because exception spec-ifications do not participate in template
argument deduction, overload resolution selects #1 and the program becomes illformed when the noexcept specification is later instantiated.
The same rules apply to exception specifications that list the potential
exception types: Click here to view code image
template
void g(T, int) throw(typename T::Nonexistent); //#1
template
void g(T, …); //#2
void test(int i)
{
g(i, i);// ERROR: chooses #1 , but the type T::Nonexistent is illformed
}

However, these “dynamic” exception specifications have been deprecated since
C++11 and were removed in C++17.

15.9 Explicit Function Template Arguments
When a function template argument cannot be deduced, it may be possible to
explicitly specify it following the function template name. For example: Click
here to view code image
template T default_value()
{
return T{};
}
int main()
{
return default_value();
}

This may be done also for template parameters that are deducible: Click here to
view code image
template void compute(T p)
{
…
}

int main()
{
compute(2);
}

Once a template argument is explicitly specified, its corresponding parameter is
no longer subject to deduction. That, in turn, allows conversions to take place on
the function call parameter that would not be possible in a deduced call. In the
example above, the argument 2 in the call compute(2) will be
implicitly converted to double.
It is possible to explicitly specify some template arguments while having
others be deduced. However, the explicitly specified ones are always matched
left-to-right with the template parameters. Therefore, parameters that cannot be
deduced (or that are likely to be specified explicitly) should be specified first.
For example: Click here to view code image
template
Out convert(In p)
{
…
}
int main() {
auto x = convert(42); // the type of parameter p is deduced,
// but the return type is explicitly specified
}

It is occasionally useful to specify an empty template argument list to ensure
the selected function is a template instance while still using deduction to
determine the template arguments: Click here to view code image
int f(int); // #1
template T f(T); // #2
int main() {
auto x = f(42); // calls #1
auto y = f<>(42); // calls #2
}

Here f(42) selects the nontemplate function because overload resolution
prefers an ordinary function over a function template if all other things are equal.
However, for f<>(42) the presence of a template argument list rules out the
nontemplate function (even though no actual template arguments are specified).
In the context of friend function declarations, the presence of an explicit
template argument list has an interesting effect. Consider the following example:
Click here to view code image

void f();
template void f();
namespace N {
class C {
friend int f(); // OK
friend int f<>(); // ERROR: return type conflict
};
}

When a plain identifier is used to name a friend function, that function is only
looked up within the nearest enclosing scope, and if it is not found there, a new
entity is declared in that scope (but it remains “invisible” except when looked up
via argument-dependent lookup (ADL); see Section 13.2.2 on page 220). That is
what happens with our first friend declaration above: No f is declared within
namespace N, and so a new N::f() is “invisibly” declared.
However, when the identifier naming the friend is followed by a template
argument list, a template must be visible through normal lookup at that point,
and normal lookup will go up any number of scopes that may be required. So,
our second declaration above will find the global function template f(), but the
compiler will then issue an error because the return types do not match (since no
ADL is performed here, the declaration created by the preceding friend function
declaration is ignored).
Explicitly specified template arguments are substituted using SFINAE
principles: If the substitution leads to an error in the immediate context of that
substitution, the function template is discarded, but other templates may still
succeed. For example: Click here to view code image
template typename T::EType f();// #1
template T f();// #2
int main() {
auto x = f();
}

Here, substituting int* for T in candidate #1 causes substitution to fail, but in
candidate #2 it succeeds, and therefore that is the candidate selected. In fact, if
after substitution exactly one candidate remains, then the name of the function
template with the explicit template arguments behaves pretty much like an
ordinary function name, including decaying to a pointer-to-function type in
many contexts. That is, replacing main() above by Click here to view code
image
int main() {
auto x = f; // OK: x is a pointer to function
}

produces a valid translation unit. However, the following example: Click here to
view code image
template void f(T);
template void f(T, T);
int main() {
auto x = f; // ERROR: there are two possible f here
}

is not valid because f does not identify a single function in that case.
Variadic function templates can be used with explicit template arguments also:
Click here to view code image
template void f(Ts … ps);
int main() {
f(1, 2, 3); // OK: 1 and 2 are converted to
double
}

Interestingly, a pack can be partially explicitly specified and partially deduced:
Click here to view code image
template void f(Ts … ps);
int main() {
f(1, 2, 3); // OK: the template arguments are 
}

15.10 Deduction from Initializers and Expressions
C++11 includes the ability to declare a variable whose type is deduced from its
initializer. It also provides a mechanism to express the type of a named entity (a
variable or function) or of an expression. These facilities turned out to be very
convenient, and C++14 and C++17 added additional variations on that theme.

15.10.1 The auto Type Specifier
The auto type specifier can be used in a number of places (primarily,
namespace scopes and local scopes) to deduce the type of a variable from its
initializer. In such cases, auto is called a placeholder type (another placeholder

type, decltype(auto), will be described a little later in Section 15.10.2 on
page 298). For example: Click here to view code image
template
void useContainer(Container const& container)
{
auto pos = container.begin();
while (pos != container.end()) {
auto& element = *pos++;
… // operate on the element
}
}

The two uses of auto in the example above eliminate the need to write two long
and potentially complicated types, the container’s iterator type and the iterator’s
value type: Click here to view code image
typename Container::const_iterator pos = container.begin();
…
typename std::iterator_traits::reference
element = *pos++;

Deduction for auto uses the same mechanism as template argument deduction.
The type specifier auto is replaced by an invented template type parameter T,
then deduction proceeds as if the variable were a function parameter and its
initializer the corresponding function argument. For the first auto example, that
corresponds to the following situation: Click here to view code image
template void deducePos(T pos);
deducePos(container.begin());

where T is the type to be deduced for auto. One of the immediate consequences
of this is that a variable of type auto will never be a reference type. The use of
auto& within the second auto example illustrates how one produces a
reference to a deduced type. Its deduction is equivalent to the following function
template and call: Click here to view code image
template deduceElement(T& element);
deduceElement(*pos++);

Here, element will always be of reference type, and its initializer cannot
produce a temporary.
It is also possible to combine auto with rvalue references, but doing so
makes it behave like a forwarding reference, because the deduction model for
auto&& fr = …; is based on a function template:
Click here to view code image

template void f(T&& fr);// auto replaced by template
parameter T

That explains the following example:
Click here to view code image
int x;
auto&& rr = 42; // OK: rvalue reference binds to an rvalue (auto =
int)
auto&& lr = x; // Also OK: auto = int& and reference collapsing makes
// lr an lvalue reference

This technique is frequently used in generic code to bind the result of a function
or operator invocation whose value category (lvalue vs. rvalue) isn’t known,
without having to make a copy of that result. For example, it is often the
preferred way to declare the iterating value in a range-based for loop: Click
here to view code image
template void g(Container c) {
for (auto&& x: c) {
…
}
}

Here we do not know the signatures of the container’s iteration interfaces, but by
using auto&& we can be confident that no additional copies are made of the
values we are iterating through. std::forward() can be invoked as
usual on the variable as usual, if perfect forwarding of the bound value is
desired. That enables a kinds of “delayed” perfect forwarding. See Section 11.3
on page 167 for an example.
In addition to references, one can combine the auto specifier to make a
variable const, a pointer, a member pointer, and so on, but auto has to be the
“main” type specifier of the declaration. It cannot be nested in a template
argument or part of the declarator that follows the type specifier. The following
example illustrates various possibilities: Click here to view code image
template struct X { T const m; };
auto const N = 400u; // OK: constant of type unsigned int
auto* gp = (void*)nullptr; // OK: gp has type void*
auto const S::*pm = &X::m; // OK: pm has type int const
X::*
X xa = X(); // ERROR: auto in template argument
int const auto::*pm2 = &X::m; // ERROR: auto is part of the
“declarator”

There are no technical reasons why C++ could not support all the cases in this
last example, but the C++ committee felt that the benefits were outweighed by

both the additional implementation cost and the potential for abuse.
In order to avoid confusing both programmers and compilers, the old use of
auto as a “storage class specifier” is no longer permitted in C++11 (and later
standards): Click here to view code image
int g() {
auto int r = 24; // valid in C++03 but invalid in C++11
return r;
}

This old use of auto (inherited from C) is always redundant. Most compilers
can usually disambiguate that use from the new use as a placeholder (even
though they don’t have to), offering a transition path from older C++ code to
newer C++ code. The old use of auto is very rare in practice, however.

Deduced Return Types
C++14 added another situation where a deducible auto placeholder type can
appear: function return types. For example: auto f() { return 42; }
defines a function with return type int (the type of 42). This can be expressed
using trailing return type syntax also: auto f() -> auto { return 42; }
In the latter case, the first auto announces the trailing return type, and the
second auto is the placeholder type to deduce. There is little reason to favor
that more verbose syntax, however.
The same mechanism exists for lambdas by default: If no return type is
specified explicitly, the lambda’s return type is deduced as if it were auto:9
Click here to view code image
auto lm = [] (int x) { return f(x); };
// same as: [] (int x) -> auto { return f(x); };

Functions can be declared separately from their definition. That is true with
functions whose return type is deduced also: Click here to view code image
auto f(); // forward declaration
auto f() { return 42; }

However, the forward declaration is of very limited use in a case like this, since
the definition must be visible at any point where the function is used. Perhaps
surprisingly, it is not valid to provide a forward declaration with a “resolved”
return type. For example: Click here to view code image
int known();

auto known() { return 42; } //ERROR: incompatible return type

Mostly, the ability to forward declare a function with a deduced return type is
only useful to be able to move a member function definition outside the class
definition because of stylistic preferences: Click here to view code image
struct S {
auto f(); // the definition will follow the class definition
};
auto S::f() { return 42; }

Deducible Nontype Parameters
Prior to C++17, nontype template arguments had to be declared with a specific
type. However, that type could be a template parameter type. For example: Click
here to view code image
template struct S;
S* ps; In this example, having to specify the type of the
nontype template argument—that is, specifying int in addition to 42—
can be tedious. C++17 therefore added the ability to declare nontype
template parameters whose actual types are deduced from the
corresponding template argument. They are declared as follows:
template struct S; which enables
S<42>* ps;

Here the type of V for S<42> is deduced to be int because 42 has type int.
Had we written S<42u> instead, the type of V would have been deduced to be
unsigned int (see Section 15.10.1 on page 294 for the details of deducing
auto type specifiers).
Note that the general constraints on the type of nontype template parameters
remain in effect. For example: Click here to view code image
S<3.14>* pd;// ERROR: floating-point nontype argument

A template definition with that kind of deducible nontype parameter often also
needs to express the actual type of the corresponding argument. That is easily
done using the decltype construct (see Section 15.10.2 on page 298). For
example: Click here to view code image
template struct Value {
using ArgType = decltype(V);
};

auto nontype template parameters are also useful to parameterize templates on

members of classes. For example: Click here to view code image
template struct PMClassT;
template struct PMClassT {
using Type = C;
};
template using PMClass = typename PMClassT::Type;
template struct CounterHandle {
PMClass& c;
CounterHandle(PMClass& c): c(c) {
}
void incr() {
++(c.*PMD);
}
};
struct S {
int i;
};
int main() {
S s{41};
CounterHandle<&S::i> h(s);
h.incr();// increases s.i
}

Here we used a helper class template PMClassT to retrieve from a pointer-tomember type its “parent” class type, using class template partial specialization10
(described in Section 16.4 on page 347). With an auto template parameter, we
only have to specify the pointer-to-member constant &S::i as a template
argument. Prior to C++17, we’d also have to specify a pointer-member-type; that
is, something like Click here to view code image
OldCounterHandle

which is unwieldy and feels redundant.
As you’d expect, that feature can also be used for nontype parameter packs:
Click here to view code image
template struct Values {
};
Values<1, 2, 3> beginning;
Values<1, ’x’, nullptr> triplet;

The triplet example shows that each nontype parameter element of the pack
can be deduced to a distinct type. Unlike the case of multiple variable declarators
(see Section 15.10.4 on page 303), there is no requirement that all the deductions

be equivalent.
If we want to force a homogeneous pack of nontype template parameters, that
is possible too: Click here to view code image
template struct HomogeneousValues {
};

However, the template argument list cannot be empty in that particular case.
See Section 3.4 on page 50 for a complete example using auto as template
parameter type.

15.10.2 Expressing the Type of an Expression with
decltype
While auto avoids the need to write out the type of the variable, it doesn’t
easily allow one to use the type of that variable. The decltype keyword
resolves that issue: It allows a programmer to express the precise type of an
expression or declaration. However, programmers should be careful about a
subtle difference in what decltype produces, depending on whether the
passed argument is a declared entity or an expression: • If e is the name of an
entity (such as a variable, function, enumerator, or data member) or a class
member access, decltype(e) yields the declared type of that entity or the
denoted class member. Thus, decltype can be used to inspect the type of a
variable.
This is useful when one wants to exactly match the type of an existing
declaration. For example, consider the following variables y1 and y2: auto x =
…;
auto y1 = x + 1;
decltype(x) y2 = x + 1; Depending on the initializer for x, y1 may or may not
have the same type as x: It depends on behavior of +. If x were deduced to an
int, y1 would also be an int. If x were deduced to a char, y1 would be an
int, because the sum of a char with 1 (which by definition is an int) is an
int. The use of decltype(x) in the type of y2 ensures that it always has the
same type as x.
• Otherwise, if e is any other expression, decltype(e) produces a type that
reflects the type and value category of that expression as follows: – If e is an
lvalue of type T, decltype(e) produces T&.

– If e is an xvalue of type T, decltype(e) produces T&&.
– If e is a prvalue of type T, decltype(e) produces T.
See Appendix B for a detailed discussion about value categories. The
difference can be demonstrated by the following example: Click here to view
code image
void g (std::string&& s)
{
// check the type of s:
std::is_lvalue_reference::value; // false
std::is_rvalue_reference::value; // true (s as declared)
std::is_same::value; // false
std::is_same::value; // true
// check the value category of s used as expression:
std::is_lvalue_reference::value; // true (s is an
lvalue)
std::is_rvalue_reference::value; // false
std::is_same::value; // true (T& signals
an lvalue)
std::is_same::value; // false
}

In the first four expressions, decltype is invoked for the variable s: Click
here to view code image
decltype(s) //declared type of entity e designated by s

which means that decltype produces the declared type of s,
std::string&&. In the last four expressions, the operand of the decltype
construct is not just a name because in every case the expression is (s), which
is a parenthesized name. In that case, the type will reflect the value category of
(s): Click here to view code image
decltype((s)) //check the value category of (s)

Our expression refers to a variable by name and is thus an lvalue:11 By the rules
above, this means that decltype(s) is an ordinary (i.e., lvalue) reference to
std::string (since the type of (s) is std::string). This is one of the
few places in C++ where parenthesizing an expression changes the meaning of
the program other than affecting the associativity of operators.
The fact that decltype computes the type of an arbitrary expression e can
be helpful in various places. Specifically, decltype(e) preserves enough
information about an expression to make it possible to describe the return type of
a function that returns the expression e itself “perfectly”: decltype computes the

type of that expression, but it also propagates the value category of the
expression to the caller of the function. For example, consider a simple
forwarding function g() that returns the results of calling f(): Click here to view
code image
??? f();
decltype(f()) g()
{
return f();
}

The return type of g() depends on the return type of f(). If f() were to return
int&, the computation of g()’s return type would first determine that the
expression f() has type int. This expression is an lvalue, because f() returns
an lvalue reference, so the declared return type of g() becomes int&.
Similarly, if the return type of f() were an rvalue reference type, the call f()
would be an xvalue, and decltype would produce an rvalue reference type
that exactly matches the type returned by f(). Essentially, this form of
decltype takes the primary characteristics of an arbitrary expression—its type
and value category—and encodes them in the type system in a manner that
enables perfect forwarding of return values.
decltype can also be useful when the value-producing auto deduction is
not sufficient. For example, assume we have a variable pos of some unknown
iterator type, and we want to create a variable element that refers to the
element stored by pos. We could use auto element = *pos; However, this will
always make a copy of the element. If we instead try auto& element = *pos; then
we will always receive a reference to the element, but the program will fail if the
iterator’s operator* returns a value.12 To address this problem, we can use
decltype so that the value- or reference-ness of the iterator’s operator* is
preserved: Click here to view code image
decltype(*pos) element = *pos; This will use a reference when the
iterator supports it and copy the value when the iterator does not.
Its primary deficiency is that it requires the initializer expression
to be written twice: once in the decltype (where it is not evaluated)
and once as the actual initializer. C++14 introduces the
decltype(auto) construct to address that issue, which we will discuss
next.

15.10.3 decltype(auto)

C++14 adds a feature that is a combination of auto and decltype:
decltype(auto). Like the auto type specifier, it is a placeholder type, and
the type of a variable, return type, or template argument is determined from the
type of the associated expression (initializer, return value, or template argument).
However, unlike just auto, which uses the rules for template argument deduction
to determine the type of interest, the actual type is determined by applying the
decltype construct directly to the expression. An example illustrates this: Click
here to view code image
int i = 42; // i has type int
int const& ref = i; // ref has type int const& and refers to i
auto x = ref; // x1 has type int and is a new independent object
decltype(auto) y = ref; // y has type int const& and also refers to i

The type of y is obtained by applying decltype to the initializer expression,
here ref, which is int const&. In contrast, the rules for auto type
deduction produce type int.
Another example shows the difference when indexing a std::vector
(which produces an lvalue): Click here to view code image
std::vector v = { 42 };
auto x = v[0]; // x denotes a new object of type int
decltype(auto) y = v[0]; // y is a reference (type int&)

This neatly addresses the redundancy in our previous example: Click here to
view code image
decltype(*pos) element = *pos; which can now be rewritten as
Click here to view code image
decltype(auto) element = *pos; It is frequently convenient for return
types too. Consider the following example: Click here to view code
image
template class Adapt
{
C container;
…
decltype(auto) operator[] (std::size_t idx) {
return container[idx];
}
};

If container[idx] produces an lvalue, we want to pass that lvalue to the
caller (who might wish to takes its address or modify it): That requires an lvalue
reference type, which is exactly what decltype(auto) resolves to. If instead

a prvalue is produced, a reference type would result in dangling references, but,
fortunately, decltype(auto) will produce an object type (not a reference
type) for that case.
Unlike auto, decltype(auto) does not allow specifiers or declarator
operators that modify its type. For example: Click here to view code image
decltype(auto)* p = (void*)nullptr; // invalid
int const N = 100;
decltype(auto) const NN = N*N; // invalid

Note also that parentheses in the initializer may be significant (since they are
significant for the decltype construct as discussed in Section 6.1 on page 91):
Click here to view code image
int x;
decltype(auto) z = x; // object of type int
decltype(auto) r = (x); // reference of type int&

This especially means that parentheses can have a severe impact on the validity
of return statements: Click here to view code image
int g();
…
decltype(auto) f() {
int r = g();
return (r); // run-time ERROR: returns reference to temporary
}

Since C++17, decltype(auto) can also be used for deducible nontype
parameters (see Section 15.10.1 on page 296). The following example illustrates
this: Click here to view code image
template class S
{
…
};
constexpr int c = 42;
extern int v = 42;
S sc; // #1 produces S<42>
S<(v)> sv; // #2 produces S<(int&)v>

In line #1 , the lack of parentheses around c causes the deducible parameter to
be of the type of c itself (i.e., int). Because c is a constant-expression of value
42, this is equivalent to S<42>. In line #2 , the parentheses cause
decltype(auto) to become a reference type int&, which can bind to the
global variable v of type int. Thus, with this declaration the class template
depends on a reference to v, and any change of the value of v might impact the
behavior of class S (see Section 11.4 on page 167 for details). (S without

parentheses, on the other hand, would be an error, because decltype(v) is
int, and therefore a constant argument of type int would be expected.
However, v doesn’t designate a constant int value.) Note that the nature of the
two cases is somewhat different; we therefore think that such nontype template
parameters are likely to cause surprise and do not anticipate that they will be
widely used.
Finally, a comment about using deduced nontype parameters in function
templates: Click here to view code image
template struct S {};
template int f(S p);
S<42> x;
int r = f(x); In this example, the type of the parameter N of
function template f<>() is deduced from the type of the nontype
parameter of S. That’s possible because a name of the form X<…> where
X is a class template is a deduced context. However, there are also
many patterns that cannot be deduced that way: Click here to view
code image
template int f(decltype(V) p);
int r1 = deduce<42>(42); // OK
int r2 = deduce(42); // ERROR: decltype(V) is a nondeduced context

In this case, decltype(V) is a nondeduced context: There is no unique value
of V that matches the argument 42 (e.g., decltype(7) produces the same
type as decltype(42)). Therefore, the nontype template parameter must be
specified explicitly to be able to call this function.

15.10.4 Special Situations for auto Deduction
There are a few special situations for the otherwise simple deduction rules of
auto. The first is when the initializer for a variable is an initializer list. The
corresponding deduction for a function call would fail, because we cannot
deduce a template type parameter from an initializer list argument: Click here to
view code image
template
void deduceT (T);
…
deduceT({ 2, 3, 4}); // ERROR
deduceT({ 1 }); // ERROR

However, if our function has a more specific parameter as follows Click here to

view code image
template
void deduceInitList(std::initializer_list);
…
deduceInitList({ 2, 3, 5, 7 }); // OK: T deduced as int

then deduction succeeds. Copy-initializing (i.e., initialization with the = token)
an auto variable with an initializer list is therefore defined in terms of that more
specific parameter: Click here to view code image
auto primes = { 2, 3, 5, 7 }; // primes is std::initializer_list
deduceT(primes); // T deduced as std::initializer_list

Before C++17, the corresponding direct-initialization of auto variables (i.e.,
without the = token) was also handled that way, but this was changed in C++17
to better match the behavior expected by most programmers: Click here to view
code image
auto oops { 0, 8, 15 }; // ERROR in C++17
auto val { 2 }; // OK: val has type int in C++17

Prior to C++17, both initializations were valid, initializing both both oops and
val of type initializer_list.
Interestingly, returning a braced initializer list for a function with a deducible
placeholder type is invalid: Click here to view code image
auto subtleError() {
return { 1, 2, 3 }; // ERROR
}

That is because an initializer list in function scope is an object that points into an
underlying array object (with the element values specified in the list) that expires
when the function returns. Allowing the construct would thus encourage what is
in effect a dangling reference.
Another special situation occurs when multiple variable declarations share the
same auto, as in the following: Click here to view code image
auto first = container.begin(), last = container.end(); In such
cases, deduction is performed independently for each declaration. In
other words, there is an invented template type parameter T1 for
first and another invented template type parameter T2 for last. Only
if both deductions succeed, and the deductions for T1 and T2 are the
same type, are the declarations well-formed. This can produce some
interesting cases:13
Click here to view code image

char c;
auto *cp = &c, d = c; // OK
auto e = c, f = c+1; // ERROR: deduction mismatch char vs. int

Here, two pairs of variables are declared with a shared auto specifier. The
declarations of cp and d deduce the same type char for auto, so this is valid
code. The declarations of e and f, however, deduce char and int due to the
promotion to int when computing c+1, and that inconsistency results in an
error.
A somewhat parallel special situation can also occur with placeholders for
deduced return types. Consider the following example: Click here to view code
image
auto f(bool b) {
if (b) {
return 42.0; // deduces return type double
} else {
return 0; // ERROR: deduction conflict
}
}

In this case, each return statement is deduced independently, but if different
types are deduced, the program is invalid. If the returned expression calls the
function recursively, deduction cannot occur and the program is invalid unless a
prior deduction already determined the return type. That means that the
following code is invalid: Click here to view code image
auto f(int n)
{
if (n > 1) {
return n*f(n-1); // ERROR: type of f(n-1) unknown
} else {
return 1;
}
}

but the following otherwise equivalent code is fine:
Click here to view code image
auto f(int n)
{
if (n <= 1) {
return 1; // return type is deduced to be int
} else {
return n*f(n-1); // OK: type of f(n-1) is int and so is type of
n*f(n-1)
}
}

Deduced return types have another special case with no counterpart in deduced
variable types or deduced nontype parameter types: Click here to view code
image
auto f1() { } // OK: return type is void
auto f2() { return; } // OK: return type is void

Both f1() and f2() are valid and have a void return type. However, if the
return type pattern cannot match void, such cases are invalid: Click here to
view code image
auto* f3() {} //ERROR: auto* cannot deduce as void

As you’d expect, any use of a function template with a deduced return type
requires the immediate instantiation of that template to determine the return type
with certainty. That, however, has a surprising consequence when it comes to
SFINAE (described in Section 8.4 on page 129 and Section 15.7 on page 284).
Consider the following example: Click here to view code image
deduce/resulttypetmpl.cpp
template
auto addA(T t, U u) -> decltype(t+u)
{
return t + u;
}
void addA(…);
template
auto addB(T t, U u) -> decltype(auto)
{
return t + u;
}
void addB(…);
struct X {
};
using AddResultA = decltype(addA(X(), X())); // OK: AddResultA is void
using AddResultB = decltype(addB(X(), X())); // ERROR: instantiation
of addB
// is ill-formed

Here, the use of decltype(auto) rather than decltype(t+u) for
addB() causes an error during overload resolution: The function body of the
addB() template must be fully instantiated to determine its return type. That
instantiation isn’t in the immediate context (see Section 15.7.1 on page 285) of

the call to addB() and therefore doesn’t fall under the SFINAE filter but results
in an outright error. It is therefore important to remember that deduced return
types are not merely a shorthand for a complex explicit return type and they
should be used with care (i.e., with the understanding that they shouldn’t be
called in the signatures of other function templates that would count on SFINAE
properties).

15.10.5 Structured Bindings
C++17 added a new feature known as structured bindings.14 It is most easily
introduced with a small example: Click here to view code image
struct MaybeInt { bool valid; int value; };
MaybeInt g();
auto const&& [b, N] = g(); // binds b and N to the members of the
result of g()

The call to g() produces a value (in this case a simple class aggregate of type
MaybeInt) that can be decomposed into “elements” (in this case, the data
members of MaybeInt). The value of that call is produced as if the bracketed
list of identifiers [b, N] were replaced by a distinct variable name. If that
name were e, the initialization would be equivalent to: auto const&& e = g();
The bracketed identifiers are then bound to the elements of e. Thus, you can
think of [b, N] as introducing names for the pieces of e (we will discuss some
details of that binding below).
Syntactically, a structured binding must always have an auto type optionally
extended by const and/or volatile qualifiers and/or &and/or && declarator
operators (but not a * pointer declarator or some other declarator construct). It is
followed by a bracketed list containing at least one identifier (reminiscent of the
“capture” list of lambdas). That in turn has to be followed by an initializer.
Three different kinds of entities can initialize a structured binding: 1. The first
case is the simple class type, where all the nonstatic data members are public (as
in our example above). For this case to apply, all the nonstatic data members
have to be public (either all directly in the class itself or all in the same,
unambiguous public base class; no anonymous unions may be involved). In that
case, the number of bracketed identifiers must equal the number of members,
and using one of these identifiers within the scope of the structured bindings
amounts to using the corresponding member of the object denoted by e (with all
the associated properties; e.g., if the corresponding member is a bit field, it is not

possible to take its address).
2. The second case corresponds to arrays. Here is an example: Click here to
view code image
int main() {
double pt[3];
auto& [x, y, z] = pt;
x = 3.0; y = 4.0; z = 0.0;
plot(pt);
}

Unsurprisingly, the bracketed initializers are just shorthand for the corresponding
elements of the unnamed array variable. The number of array elements must
equal the number of bracketed initializers.
Here is another example:
Click here to view code image
auto f() -> int(&)[2]; // f() returns reference to int array
auto [ x, y ] = f(); // #1
auto& [ r, s ] = f(); // #2

Line #1 is special: Ordinarily, the entity e described earlier would be deduced
from the following for this case: auto e = f(); However, that would deduce the
decayed pointer to the array, which is not what happens when performing the
structured binding of an array. Instead, e is deduced to be a variable of array type
corresponding to the type of the initializer. Then that array is copied from the
initializer, element by element: That is a somewhat unusual concept for built-in
arrays.15 Finally, x and y become aliases for the expressions e[0] and e[1],
respectively.
Line #2 , does not involve array copying and follows the usual rules for auto.
So the hypothetical e is declared as follows: auto& e = f(); which yields a
reference to an array, and x and y again become aliases for the expressions e[0]
and e[1], respectively (which are lvalues referring directly to the elements of
the array produced by the call to f()).
3. Finally, a third option allows std::tuple-like classes to have their
elements decomposed through a template-based protocol using get<>(). Let
E be the type of the expression (e) with e declared as above. Because E is the
type of an expression, it is never a reference type. If the expression
std::tuple_size::value is a valid integral constant expression, it
must equal the number of bracketed identifiers (and the protocol kicks in,
taking precedence over the first option but not the second option for arrays).

Let’s denote the bracketed identifiers by n0, n1, n2, and so forth. If e has any
member named get, then the behavior is as if these identifiers are declared as
Click here to view code image
std::tuple_element::type& ni = e.get();

if e was deduced to have a reference type, or Click here to view code image
std::tuple_element::type&& ni = e.get();

otherwise. If e has no member get, then the corresponding declarations
become instead Click here to view code image
std::tuple_element::type& ni = get(e);

or
Click here to view code image
std::tuple_element::type&& ni = get(e);

where get is only looked up in associated classes and namespaces. (In all
cases, get is assumed to be a template and therefore the < follows is an angle
bracket.) The std::tuple, std::pair, and std::array templates all
implement this protocol, making, for example, the following code valid: Click
here to view code image
#include 
std::tuple bi{true, 42};
auto [b, i] = bi;
int r = i; // initializes r to 42

However, it is not difficult to add specializations of std::tuple_size,
std::tuple_element, and a function template or member function
template get<>() that will make this mechanism work for an arbitrary class or
enumeration type. For example: Click here to view code image
#include 
enum M {};
template<> class std::tuple_size {
public:
static unsigned const value = 2; // map M to a pair of values
};
template<> class std::tuple_element<0, M> {
public:
using type = int; // the first value will have type int
};

template<> class std::tuple_element<1, M> {
public:
using type = double; // the second value will have type double
};
template auto get(M);
template<> auto get<0>(M) { return 42; }
template<> auto get<1>(M) { return 7.0; }
auto [i, d] = M(); // as if: int&& i = 42; double&& d = 7.0;

Note that you only need to include  to use the two tuple-like access
helper functions std::tuple_size<> and std::tuple_element<>.
In addition, note that the third case above (using the tuple-like protocol)
performs an actual initialization of the bracketed initializers and the bindings are
actual reference variables; they are not just aliases for another expression (unlike
the first two cases using simple class types and arrays). That’s of interest because
that reference initialization could go wrong; for example, it might throw an
exception, and that exception is now unavoidable. However, the C++
standardization committee also discussed the possibility of not associating the
identifiers with initialized references but instead having each later use of the
identifiers evaluate a get<>() expression. That would have allowed structured
bindings to be used with types where the “first” value must be tested before
accessing the “second” value (e.g., based on std::optional).

15.10.6 Generic Lambdas
Lambdas have quickly become one of the most popular C++11 features, in part
because they significantly ease the use of the functional constructs in the C++
standard library and in many other modern C++ libraries, due largely to their
concise syntax. However, within templates themselves, lambdas can become
fairly verbose due to the need to spell out the parameter and result types. For
example, consider a function template that finds the first negative value from a
sequence: Click here to view code image
template
Iter findNegative(Iter first, Iter last)
{
return std::find_if(first, last,
[] (typename std::iterator_traits::value_type
value) {
return value < 0;
});

}

In this function template, the most complicated part of the lambda (by far) is its
parameter type. C++14 introduced the notion of “generic” lambdas, where one
or more of the parameter types use auto to deduce the type rather than writing
it specifically: Click here to view code image
template
Iter findNegative(Iter first, Iter last)
{
return std::find_if(first, last,
[] (auto value) {
return value < 0;
});
}

An auto in a parameter of a lambda is handled similarly to an auto in the type
of a variable with an initializer: It is replaced by an invented template type
parameter T. However, unlike in the variable case, the deduction isn’t performed
immediately because the argument isn’t known at the time the lambda is created.
Instead, the lambda itself becomes generic (if it wasn’t already), and the
invented template type parameter is added to its template parameter list. Thus,
the lambda above can be invoked with any argument type, so long as that
argument type supports the < 0 operation whose result is convertible to bool.
For example, this lambda could be called with either an int or a float value.
To understand what it means for a lambda to be generic, we first consider the
implementation model for a nongeneric lambda. Given the lambda [] (int
i) {
return i < 0;
}
the C++ compiler translates this expression into an instance of a newly invented
class specific to this lambda. This instance is called a closure or closure object,
and the class is called a closure type. The closure type has a function call
operator, and hence the closure is a function object.16 For this lambda, the
closure type would look something like the following (we leave out the
conversion function to a pointer-to-function value for brevity and simplicity):
Click here to view code image
class SomeCompilerSpecificNameX
{
public:
SomeCompilerSpecificNameX(); // only callable by the compiler
bool operator() (int i) const
{
return i < 0;

}
};

If you check the type category for a lambda, std::is_class<> will yield
true (see Section D.2.1 on page 705).
A lambda expression thus results in an object of this class (the closure type).
For example: foo(…,
[] (int i) {
return i < 0;
});
creates an object (the closure) of the internal compiler-specific class
SomeCompilerSpecificNameX: Click here to view code image
foo(…,
SomeCompilerSpecificNameX{}); // pass an object of the closure type

If the lambda were to capture local variables:
int x, y;
…
[x,y](int i) {
return i > x && i < y;
}

those captures would be modeled as initializing members of the associated class
type: Click here to view code image
class SomeCompilerSpecificNameY {
private
int _x, _y;
public:
SomeCompilerSpecificNameY(int x, int y) //only callable by the
compiler
: _x(x), _y(y) {
}
bool operator() (int i) const {
return i > _x && i < _y;
}
};

For a generic lambda, the function call operator becomes a member function
template, so our simple generic lambda [] (auto i) {
return i < 0;
}
is transformed into the following invented class (again, ignoring the conversion
function, which becomes a conversion function template in the generic lambda
case): Click here to view code image

class SomeCompilerSpecificNameZ
{
public:
SomeCompilerSpecificNameZ();// only callable by compiler
template
auto operator() (T i) const
{
return i < 0;
}
};

The member function template is instantiated when the closure is invoked, which
is usually not at the point where the lambda expression appears. For example:
Click here to view code image
#include 
template void invoke (F f, Ts… ps)
{
f(ps…);
}
int main()
{
invoke([](auto x, auto y) {
std::cout << x+y << ’\n’
},
21, 21);
}

Here the lambda expression appears in main(), and that’s where an associated
closure is created. However, the call operator of the closure isn’t instantiated at
that point. Instead, the invoke() function template is instantiated with the
closure type as the first parameter type and int (the type of 21) as a second and
third parameter type. That instantiation of invoke is called with a copy of the
closure (which is still a closure associated with the original lambda), and it
instantiates the operator() template of the closure to satisfy the instantiated
call f(ps…).

15.11 Alias Templates
Alias templates (see Section 2.8 on page 39) are “transparent” with respect to
deduction. That means that wherever an alias template appears with some
template arguments, that alias’s definition (i.e., the type to the right of the =) is
substituted with the arguments, and the resulting pattern is what is used for the

deduction. For example, template argument deduction succeeds in the following
three calls: Click here to view code image
deduce/aliastemplate.cpp
template
class Stack;
template
using DequeStack = Stack>;
template
void f1(Stack);
template
void f2(DequeStack);
template
void f3(Stack); // equivalent to f2
void test(DequeStack intStack)
{
f1(intStack); // OK: T deduced to int, Cont deduced to std::deque
f2(intStack); // OK: T deduced to int
f3(intStack); // OK: T deduced to int
}

In the first call (to f1()), the use of the alias template DequeStack in the
type of intStack has no effect on deduction: The specified type
DequeStack is treated as its substituted type Stack>. The second and third calls have the same deduction
behavior, because DequeStack in f2() and the substituted form
Stack> in f3() are equivalent. For the purposes of
template argument deduction, template aliases are transparent: They can be used
to clarify and simplify code but have no effect on how deduction operates.
Note that this is possible because alias templates cannot be specialized (see
Chapter 16 for details on the topic of template specialization). Suppose the
following were possible: Click here to view code image
template using A = T;
template<> using A = void; // ERROR, but suppose it were
possible…

Then we would not be able to match A against type void and conclude that
T must be void because both A and A are equivalent to void.
The fact that this is not possible guarantees that each use of an alias can be

generically expanded according to its definition, which allows it to be
transparent for deduction.

15.12 Class Template Argument Deduction
C++17 introduces a new kind of deduction: Deducing the template parameters of
a class type from the arguments specified in an initializer of a variable
declaration or a functional-notation type conversion. For example: Click here to
view code image
Click here to view code image
template
class C
{
public:
// constructor for 0, 1, 2, or 3 arguments:
C (T1 x = T1{}, T2 y = T2{}, T3 z = T3{});
…
};
C c1(22, 44.3, "hi"); // OK in C++17: T1 is int, T2 is double, T3 is
char const*
C c2(22, 44.3); // OK in C++17: T1 is int, T2 and T3 are double
C c3("hi", "guy"); // OK in C++17: T1, T2, and T3 are char const*
C c4; // ERROR: T1 and T2 are undefined
C c5("hi"); // ERROR: T2 is undefined

Note that all parameters must be determined by the deduction process or from
default arguments. It is not possible to explicitly specify a few arguments and
deduce others. For example: Click here to view code image
C c10("hi","my", 42); // ERROR: only T1 explicitly specified,
T2 not deduced
C<> c11(22, 44.3, 42); // ERROR: neither T1 nor T2 explicitly
specified
C c12("hi","my"); // OK: T1 and T2 are deduced, T3 has
default

15.12.1 Deduction Guides
Consider first a small change to our earlier example from Section 15.8.2 on page
288: Click here to view code image
template
class S {

private:
T a;
public:
S(T b) : a(b) {
}
};
template S(T) -> S; // deduction guide
S x{12}; // OK since C++17, same as: S x{12};
S y(12); // OK since C++17, same as: S y(12);
auto z = S{12}; // OK since C++17, same as: auto z = S{12};

Note in particular the addition of a new template-like construct called a
deduction guide. It looks a little like a function template, but it differs
syntactically from a function template in a few ways: • The part that looks like a
trailing return type cannot be written as a traditional return type. We call the type
it designates (S in our example) as the guided type.
• There is no leading auto keyword to indicate that a trailing return type
follows.
• The “name” of a deduction guide must be the unqualified name of a class
template declared earlier in the same scope.
• The guided type of the guide must be a template-id whose template name
corresponds to the guide name.
• It can be declared with the explicit specifier.
In the declaration S x(12); the specifier S is called a placeholder class type.17
When such a placeholder is used, the name of the variable being declared must
follow immediately and that in turn must be followed by an initializer. The
following is therefore invalid: Click here to view code image
S* p = &x;// ERROR: syntax not permitted

With the guide as written in the example, the declaration S x(12); deduces
the type of the variable by treating the deduction guides associated with class S
as an overload set and attempting overload resolution with the initializer against
that overload set. In this case, the set has only one guide in it, and it successfully
deduces T to be int and the guide’s guided type to be S.18 That guided
type is therefore selected as the type of the declaration.
Note that in the case of multiple declarators following a class template name
requiring deduction, the initializer for each of those declarators has to produce
the same type. For example, with the declarations above: Click here to view
code image

S s1(1), s2(2.0);// ERROR: deduces S both as S and S

This is similar to the constraints when deducing the C++11 placeholder type
auto.
In the previous example, there is an implicit connection between the deduction
guide we declared and the constructor S(T b) declared in class S. However,
such a connection is not required, which means that deduction guides can be
used with aggregate class templates: Click here to view code image
template
struct A
{
T val;
};
template A(T) -> A; // deduction guide

Without the deduction guide, we are always required (even in C++17) to specify
explicit template arguments: Click here to view code image
A
A
A
A a4 =

a1{42}; // OK
a2(42); // ERROR: not aggregate initialization
a3 = {42}; // OK
42; // ERROR: can’t deduce type

But with the guide as written above, we can write:
A a4 = { 42 };// OK

A subtlety in cases like these, however, is that the initializer must still be a
valid aggregate initializer; that is, it must use a braced initializer list. The
following alternatives are therefore not permitted: Click here to view code image
A a5(42); // ERROR: not aggregate initialization
A a6 = 42; // ERROR: not aggregate initialization

15.12.2 Implicit Deduction Guides
Quite often, a deduction guide is desirable for every constructor in a class
template. That led the designers of class template argument deduction to include
an implicit mechanism for the deduction. It is equivalent to introducing for every
constructor and constructor template of the primary class template19 an implicit
deduction guide as follows: • The template parameter list for the implicit guide
consists of the template parameters for the class template, followed, in the
constructor template case, by the template parameters of the constructor

template. The template parameters of the constructor template retain any default
arguments.
• The “function-like” parameters of the guide are copied from the constructor or
constructor template.
• The guided type of the guide is the name of the template with arguments that
are the template parameters taken from the class template.
Let’s apply this on our original simple class template:
Click here to view code image
template
class S {
private:
T a;
public:
S(T b) : a(b) {
}
};

The template parameter list is typename T, the function-like parameter list
becomes just (T b), and the guided type is then S. Thus, we obtain a guide
that’s equivalent to the user-declared guide we wrote earlier: That guide was
therefore not required to achieve our desired effect! That is, with just the simple
class template as originally written (and no deduction guide), we can validly
write S x(12); with the expected result that x has type S.
Deduction guides have an unfortunate ambiguity. Consider again our simple
class template S and the following initializations: S x{12}; // x has type
S
S y{s1}; S z(s1);
We already saw that x has type S, but what should the type of x and y
be? The two types that arise intuitively are S> and S. The
committee decided somewhat controversially that it should be S in both
cases. Why is this controversial? Consider a similar example with a vector
type: Click here to view code image
std::vector v{1, 2, 3}; // vector, not surprising
std::vector w2{v, v}; // vector>
std::vector w1{v}; // vector!

In other words, a braced initializer with one element deduces differently from a
braced initializer with multiple elements. Often, the one-element outcome is
what is desired, but the inconsistency is somewhat subtle. In generic code,
however, it is easy to miss the subtlety: Click here to view code image
template

auto f(T p, Ts… ps) {
std::vector v{p, ps…}; // type depends on pack length
…
}

Here it is easy to forget that if T is deduced to be a vector type, the type of v will
be fundamentally different depending on whether ps is an empty or a nonempty
pack.
The addition of implicit template guides themselves was not without
controversy. The main argument against their inclusion is that the feature
automatically adds interfaces to existing libraries. To understand this, consider
once more our simple class template S above. Its definition has been valid since
templates were introduced in C++. Suppose, however, that the author of S
expands library causing S to be defined in a more elaborate way: Click here to
view code image
template
struct ValueArg {
using Type = T;
};
template< typename T>
class S {
private:
T a;
public:
using ArgType = typename ValueArg::Type;
S(ArgType b) : a(b) {
}
};

Prior to C++17, transformations like these (which are not uncommon) did not
affect existing code. However, in C++17 they disable implicit deduction guides.
To see this, let’s write a deduction guide corresponding to the one produced by
the implicit deduction guide construction process outlined above: The template
parameter list and the guided type are unchanged, but the function-like
parameter is now written in terms of ArgType, which is typename
ValueArg::Type: Click here to view code image
template S(typename ValueArg::Type) -> S; Recall from
Section 15.2 on page 271 that a name qualifier like ValueArg:: is
not a deduced context. So a deduction guide of this form is useless
and will not resolve a declaration like S x(12);. In other words, a
library writer performing this kind of transformation is likely to
break client code in C++17.

What is a library writer to do given that situation? Our advice is to carefully

consider for each constructor whether you want to offer it as a source for an
implicit deduction guide for the remainder of the library’s lifetime. If not,
replace each instance of a deducible constructor parameter of type X by
something like typename ValueArg::Type. There is unfortunately no
simpler way to “opt out” of implicit deduction guides.

15.12.3 Other Subtleties
Injected Class Names
Consider the following example:
Click here to view code image
template struct X {
template X(Iter b, Iter e);
template auto f(Iter b, Iter e) {
return X(b, e); // What is this?
}
};

This code is valid C++14: The X in X(b, e) is the injected class name and is
equivalent to X in this context (see Section 13.2.3 on page 221). The rules
for class template argument deduction, however, would naturally make that X
equivalent to X.
In order to maintain backward compatibility, however, class template
argument deduction is disabled if the name of the template is an injected class
name.

Forwarding References
Consider another example:
Click here to view code image
template struct Y {
Y(T const&);
Y(T&&);
};
void g(std::string s) {
Y y = s;
}

Clearly, the intent here is that we deduce T to be std::string through the
implicit deduction guide associated with the copy constructor. Writing the
implicit deduction guides as explicitly declared guides reveals a surprise,
however: Click here to view code image
template Y(T const&) -> Y; // #1
template Y(T&&) -> Y; // #2

Recall from Section 15.6 on page 277 that T&& behaves specially during
template argument deduction: As a forwarding reference, it causes T to be
deduced to a reference type if the corresponding call argument is an lvalue. In
our example above, the argument in the deduction process is the expression s,
which is an lvalue. Implicit guide #1 deduces T to be std::string but
requires the argument to be adjusted from std::string to std::string
const. Guide #2 , however, would normally deduce T to be a reference type
std::string& and produce a parameter of that same type (because of the
reference collapsing rule), which is a better match because no const must be
added for type adjustment purposes.
This outcome would be rather surprising and likely would result in
instantiation errors (when the class template parameter is used in contexts that do
not permit reference types) or, worse, silent production of misbehaving
instantiations (e.g., producing dangling references).
The C++ standardization committee therefore decided to disable the special
deduction rule for T&& when performing deduction for implicit deduction guides
if the T was originally a class template parameter (as opposed to a constructor
template parameter; for those, the special deduction rule remains). The example
above thus deduces T to be std::string, as would be expected.
The explicit Keyword
A deduction guide can be declared with the keyword explicit. It is then
considered only for direct-initialization cases, not for copy-initialization cases.
For example: Click here to view code image
template struct Z {
Z(T const&);
Z(T&&);
};
template Z(T const&) -> Z; // #1
template explicit Z(T&&) -> Z; // #2

Z z1 = 1; // only considers #1 ; same as: Z z1 = 1;
Z z2{2}; // prefers #2 ; same as: Z z2{2};

Note how the initialization of z1 is copy-initialization, and therefore the
deduction guide #2 is not considered because it is declared explicit.
Copy Construction and Initializer Lists
Consider the following class template:
Click here to view code image
template struct Tuple {
Tuple(Ts…);
Tuple(Tuple const&);
};

To understand the effect of the implicit guides, let’s write them as explicit
declarations: Click here to view code image
template Tuple(Ts…) -> Tuple;
template Tuple(Tuple const&) -> Tuple; Now
consider some examples:
auto x = Tuple{1,2}; This clearly selects the first guide and
therefore the first constructor: x is therefore a Tuple.
Let’s continue with some examples that use syntax that is suggestive
of copying x: Tuple a = x;

Tuple b(x);
For both a and b, both guides match. The first guide selects type
Tuple, whereas the guide associated with the copy
constructor produces Tuple. Fortunately, the second guide is a
better match, and therefore both a and b are copy-constructed from x.
Now, consider some examples using braced initializer lists: Tuple c{x,
x};
Tuple d{x};
The first of these examples (x) can only match the first guide, and so produces
Tuple, Tuple>. That is entirely
intuitive and not a surprise. That would suggest that the second example should
deduce d to be of type Tuple>. Instead, however, it is treated
as a copy construction (i.e., the second implicit guide is preferred). This also
happens with functional-notation casts: auto e = Tuple{x}; Here, e is deduced to
be a Tuple, not a Tuple>.

Guides Are for Deduction Only
Deduction guides are not function templates: They are only used to deduce
template parameters and are not “called.” That means that the difference
between passing arguments by reference or by value is not important for guiding
declarations. For example: Click here to view code image
template struct X {
…
};
template struct Y {
Y(X const&);
Y(X&&);
};
template Y(X) -> Y; Note how the deduction guide
does not quite correspond to the two constructors of Y. However, that
does not matter, because the guide is only used for deduction. Given
a value xtt of type X— lvalue or rvalue—it will select the
deduced type Y. Then, initialization will perform overload
resolution on the constructors of Y to decide which one to call
(which will depend on whether xtt is an lvalue or an rvalue).

15.13 Afternotes
Template argument deduction for function templates was part of the original
C++ design. In fact, the alternative provided by explicit template arguments did
not become part of C++ until many years later.
SFINAE is a term that was introduced in the first edition of this book. It
quickly became very popular throughout the C++ programming community.
However, in C++98, SFINAE was not as powerful as it is now: It only applied to
a limited set of type operations and did not cover arbitrary expressions or access
control. As more template techniques began to rely on SFINAE (see Section
19.4 on page 416), the need to generalize the SFINAE conditions became
apparent. Steve Adamczyk and John Spicer developed the wording that achieved
that in C++11 (through paper N2634). Although the wording changes in the
standard are relatively small, the implementation effort in some compilers turned
out to be disproportionaly large.
The auto type specifier and the decltype construct were among the
earliest additions to C++03 that would eventually become C++11. Their
development was spearheaded by Bjarne Stroustrup and Jaakko J¨arvi (see their

papers N1607 for the auto type specifier and N2343 for decltype).
Stroustrup had already considered the auto syntax in his original
implementation of C++ (known as Cfront). When the feature was added to
C++11, the original meaning of auto as a storage specifier (inherited from the
C language) was retained and a disambiguation rule decided how the keyword
should be interpreted. While implementing the feature in the Edison Design
Group’s front end, David Vandevoorde discovered that this rule was likely to
produce surprises for C++11 programmers (N2337). After examining the issue,
the standardization committee decided to drop the traditional use of auto
altogether (everywhere the keyword auto is used in a C++03 program, it could
just as well be left out) through paper N2546 (by David Vandevoorde and Jens
Maurer). This was an unusual precedent of dropping a feature from the language
without first deprecating it, but it has since been proven to be the right decision.
GNU’s GCC compiler accepted an extension typeof not unlike the
decltype feature, and programmers had found it useful in template
programming. Unfortunately, it was a feature developed in the context of the C
language and not a perfect fit for C++. The C++ committee could therefore not
incorporate it as is, but neither could it modify it, because that would break
existing code relying on GCC’s behavior. That is why decltype is not spelled
typeof. Jason Merrill and others have made strong arguments that it would be
preferable to have distinct operators instead of the current subtle difference
between decltype(x) and decltype((x)), but they were not convincing
enough to change the final specification.
The ability to declare nontype template parameters with auto in C++17 was
primarily developed by Mike Spertus, with help from James Touton, David
Vandevoorde, and many others. The specification changes for the feature are
written up in P0127R2. Interestingly, it is not clear that the ability to use
decltype(auto) instead of auto was intentionally made part of the
language (it was apparently not discussed by the committee, but it falls out of the
specification).
Mike Spertus also drove the development of class template argument
deduction in C++17, with Richard Smith and Faisal Vali contributing significant
technical ideas (including the idea of deduction guides). Paper P0091R3 has the
specification that was voted into the working paper for the next language
standard.
Structured bindings were primarily driven by Herb Sutter, who wrote paper
P0144R1 with Gabriel Dos Reis and Bjarne Stroustrup to propose the feature.
Many tweaks were made during committee discussions, including the use of

brackets to delimit the decomposing identifiers. Jens Maurer translated the
proposal into a final specification for the standard (P0217R3).
1 In this case, deduction failure leads to an error. However, this falls under the
SFINAE principle (see Section 8.4 on page 129): If there were another
function for which deduction succeeds, the code could be valid.
2 Decay is the term used to refer to the implicit conversion of function and array
types to pointer types.
3 If a pack expansion occurs anywhere else in a function parameter list or
template argument list, that pack expansion is considered a nondeduced
context.
4 Reference collapsing was introduced into the C++ 2003 standard when it was
noted that the standard pair class template would not work with reference
types. The 2011 standard extended reference collapsing further by
incorporating rules for rvalue references.
5 Bit fields are an exception.
6 Treating a parameter of rvalue reference type as an lvalue is intended as a
safety feature, because anything with a name (like a parameter) can easily be
referenced multiple times in a function. If each of those references could be
implicitly treated as an rvalue, its value could be destroyed unbeknownst to
the programmer. Therefore, one must explicitly state when a named entity
should be treated as an rvalue. For this purpose, the C++ standard library
function std::move treats any value as an rvalue (or, more precisely, an
xvalue; see Appendix B for details).
7 SFINAE also applies to the substitution of partial class template
specializations. See Section 16.4 on page 347.
8 The immediate context includes many things, including various kinds of
lookup, alias template substitutions, overload resolution, etc. Arguably the
term is a bit of a misnomer, because some of the activities it includes are not
closely tied to the function template being substituted.
9 Although C++14 introduced deduced return types in general, they were
already available to C++11 lambdas using a specification that was not worded
in terms of deduction. In C++14, that specification was updated to use the
general auto deduction mechanism (from a programmer’s point of view,
there is no difference).
10 The same technique can be used to extract the associated member type:
Instead of using Type = C; use using Type = M;.
11 As mentioned elsewhere, treating a parameter of rvalue reference type as an

lvalue rather than an xvalue is intended as a safety feature, because anything
with a name (like a parameter) can easily be referenced multiple times in a
function. If it were an xvalue, its first use might cause its value to be “moved
away,” causing surprising behavior for every subsequent use. See Section 6.1
on page 91 and Section 15.6.3 on page 280.
12 When we used the latter formulation in our introductory example of auto,
we implicitly assumed that the iterators produced references to some
underlying storage. While this is generally true for container iterator (and
required by the standard containers other than vector), it is not the
case for all iterators.
13 This example does not use our usual style for placing the * immediately
adjacent to the auto, because it could mislead the reader into thinking we are
declaring two pointers. On the other hand, the opacity of these declarations is
a good argument for being conservative when declaring multiple entities in a
single declaration.
14 The term structured bindings was used in the original proposal for the feature
and was also eventually used for the formal specification in the language.
Briefly, however, that specification used the term decomposition declarations
instead.
15 The other two places where built-in arrays are copied are lambda captures
and generated copy constructors.
16 This translation model of lambdas is actually used in the specification of the
C++ language, making it both a convenient and an accurate description of the
semantics. Captured variables become data members, the conversion of a
noncapturing lambda to a function pointer is modeled as a conversion function
in the class, and so on. And because lambdas are function objects, whenever
rules for function objects are defined, they also apply to lambdas.
17 Note the distinction between a placeholder type, which is auto or
decltype(auto) and can resolve to any kind of type, and a placeholder
class type, which is a template name and can only resolve to a class type that
is an instance of the indicated template.
18 As with ordinary function template deduction, SFINAE could apply if, for
example, substituting the deduced arguments in the guided type failed. That is
not the case in this simple example.
19 Chapter 16 introduces the ability to “specialize” class templates in various
ways. Such specializations do not participate in class template argument
deduction.

Chapter 16
Specialization and Overloading
So far we have studied how C++ templates allow a generic definition to be
expanded into a family of related classes, functions, or variables. Although this
is a powerful mechanism, there are many situations in which the generic form of
an operation is far from optimal for a specific substitution of template
parameters.
C++ is somewhat unique among other popular programming languages with
support for generic programming because it has a rich set of features that enable
the transparent replacement of a generic definition by a more specialized facility.
In this chapter we study the two C++ language mechanisms that allow pragmatic
deviations from pure generic-ness: template specialization and overloading of
function templates.

16.1 When “Generic Code” Doesn’t Quite Cut It
Consider the following example:
Click here to view code image
template
class Array {
private:
T* data;
…
public:
Array(Array const&);
Array& operator= (Array const&);
void exchangeWith (Array* b) {
T* tmp = data;
data = b->data;
b->data = tmp;
}
T& operator[] (std::size_t k) {
return data[k];
}
…

};
template inline
void exchange (T* a, T* b)
{
T tmp(*a);
*a = *b;
*b = tmp;
}

For simple types, the generic implementation of exchange() works well.
However, for types with expensive copy operations, the generic implementation
may be much more expensive—both in terms of machine cycles and in terms of
memory usage—than an implementation that is tailored to the particular, given
structure. In our example, the generic implementation requires one call to the
copy constructor of Array and two calls to its copy-assignment operator.
For large data structures these copies can often involve copying relatively large
amounts of memory. However, the functionality of exchange() could
presumably often be replaced just by swapping the internal data pointers, as is
done in the member function exchangeWith().

16.1.1 Transparent Customization
In our previous example, the member function exchangeWith() provides an
efficient alternative to the generic exchange() function, but the need to use a
different function is inconvenient in several ways: 1. Users of the Array class
have to remember an extra interface and must be careful to use it when possible.
2. Generic algorithms can generally not discriminate between various
possibilities. For example: Click here to view code image
template
void genericAlgorithm(T* x, T* y)
{
…
exchange(x, y); // How do we select the right algorithm?
…
}

Because of these considerations, C++ templates provide ways to customize
function templates and class templates transparently. For function templates, this
is achieved through the overloading mechanism. For example, we can write an
overloaded set of quickExchange() function templates as follows:

template
void quickExchange(T* a, T* b) // #1
{
T tmp(*a);
*a = *b;
*b = tmp;
}
template
void quickExchange(Array* a, Array* b) // #2
{
a->exchangeWith(b);
}
void demo(Array* p1, Array* p2)
{
int x=42, y=-7;
quickExchange(&x, &y); // uses #1
quickExchange(p1, p2); // uses #2
}

The first call to quickExchange() has two arguments of type int*, and
therefore deduction succeeds only with the first template, declared at point #1 ,

when T is substituted by int. There is therefore no doubt regarding which
function should be called. In contrast, the second call can be matched with either
template: Viable functions for the call quickExchange(p1, p2) are
obtained both when substituting Array for T in the first template and
when substituting int in the second template. Furthermore, both substitutions
result in functions with parameter types that exactly match the argument types of
the second call. Ordinarily, this would lead us to conclude that the call is
ambiguous, but (as we will discuss later) the C++ language considers the second
template to be “more specialized” than the first. All other things being equal,
overload resolution prefers the more specialized template and hence selects the
template at point #2 .

16.1.2 Semantic Transparency
The use of overloading as shown in the previous section is very useful in
achieving transparent customization of the instantiation process, but it is
important to realize that this “transparency” depends a great deal on the details
of the implementation. To illustrate this, consider our quickExchange()
solution. Although both the generic algorithm and the one customized for
Array types end up swapping the values that are being pointed to, the side
effects of the operations are very different. This is dramatically illustrated by
considering some code that compares the exchange of struct objects with the
exchange of Arrays:

struct S {
int x;
} s1, s2;
void distinguish (Array a1, Array a2)
{
int* p = &a1[0];
int* q = &s1.x;
a1[0] = s1.x = 1;
a2[0] = s2.x = 2;
quickExchange(&a1, &a2); // *p == 1 after this (still)
quickExchange(&s1, &s2); // *q == 2 after this
}

This example shows that a pointer p into the first Array becomes a pointer into
the second array after quickExchange() is called. However, the pointer into
the non-Array s1 remains pointing into s1 even after the exchange operation:
Only the values that were pointed to were exchanged. The difference is
significant enough that it may confuse clients of the template implementation.
The prefix quick_ is helpful in attracting attention to the fact that a shortcut
may be taken to realize the desired operation. However, the original generic
exchange() template can still have a useful optimization for Arrays:
Click here to view code image
template
void exchange (Array* a, Array* b)
{
T* p = &(*a)[0];
T* q = &(*b)[0];
for (std::size_t k = a->size(); k-- != 0; ) {
exchange(p++, q++);
}
}

The advantage of this version over the generic code is that no (potentially) large
temporary Array is needed. The exchange() template is called
recursively so that good performance is achieved even for types such as
Array>. Note also that the more specialized version of the
template is not declared inline because it does a considerable amount of work
of its own, whereas the original generic implementation is inline because it
performs only a few operations (each of which is potentially expensive).

16.2 Overloading Function Templates

In the previous section we saw that two function templates with the same name
can coexist, even though they may be instantiated so that both have identical
parameter types. Here is another simple example of this:

details/funcoverload1.hpp
template
int f(T)
{
return 1;
}
template
int f(T*)
{
return 2;
}

When T is substituted by int* in the first template, a function is obtained that
has exactly the same parameter (and return) types as the one obtained by
substituting int for T in the second template. Not only can these templates
coexist, their respective instantiations can coexist even if they have identical
parameter and return types.
The following demonstrates how two such generated functions can be called
using explicit template argument syntax (assuming the previous template
declarations): Click here to view code image
details/funcoverload1.cpp
#include 
#include "funcoverload1.hpp"
int main()

{
std::cout << f((int*)nullptr); // calls f(T)
std::cout << f((int*)nullptr); // calls f(T*)
}

This program has the following output:
12
To clarify this, let’s analyze the call f((int*)nullptr) in detail.
The syntax f() indicates that we want to substitute the first template
parameter of the template f() with int* without relying on template argument
deduction. In this case there is more than one template f(), and therefore an
overload set is created containing two functions generated from templates:
f(int*) (generated from the first template) and f(int**) (generated
from the second template). The argument to the call (int*)nullptr has type int*.
This matches only the function generated from the first template, and hence that
is the function that ends up being called.
For the second call, on the other hand, the created overloading set contains
f(int) (generated from the first template) and f(int*)
(generated from the second template), so that only the second template matches.

16.2.1 Signatures
Two functions can coexist in a program if they have distinct signatures. We
define the signature of a function as the following information:1. The unqualified
name of the function (or the name of the function template from which it was
generated) 2. The class or namespace scope of that name and, if the name has
internal linkage, the translation unit in which the name is declared 3. The
const, volatile, or const volatile qualification of the function (if it
is a member function with such a qualifier) 4. The & or && qualification of the
function (if it is a member function with such a qualifier) 5. The types of the
function parameters (before template parameters are substituted if the function is
generated from a function template) 6. Its return type, if the function is generated
from a function template 7. The template parameters and the template
arguments, if the function is generated from a function template This means that
the following templates and their instantiations could, in principle, coexist in the
same program: Click here to view code image
template
void f1(T1, T2);

template
void f1(T2, T1);
template
long f2(T);
template
char f2(T); However, they cannot always be used when they’re declared
in the same scope because instantiating both creates an overload
ambiguity. For example, calling f2(42) when both the templates above
are declared will clearly create an ambiguity. Another example is
illustrated below:

#include 
template
void f1(T1, T2)
{
std::cout << "f1(T1, T2)\n";
}
template
void f1(T2, T1)
{
std::cout << "f1(T2, T1)\n";
}
// fine so far

int main()
{
f1(’a’, ’b’); // ERROR: ambiguous
}

Here, the function
Click here to view code image
f1(T1, T2)

can coexist with the function
Click here to view code image
f1(T2, T1)

but overload resolution will never prefer one over the other. If the templates
appear in different translation units, then the two instantiations can actually exist
in the same program (and, e.g., a linker should not complain about duplicate
definitions because the signatures of the instantiations are distinct): Click here to
view code image
// translation unit 1:
#include 
template
void f1(T1, T2)
{
std::cout << "f1(T1, T2)\n";
}
void g()
{
f1(’a’, ’b’);
}
// translation unit 2:
#include 
template
void f1(T2, T1)
{
std::cout << "f1(T2, T1)\n";
}
extern void g(); // defined in translation unit 1
int main()
{
f1(’a’, ’b’);
g();
}

This program is valid and produces the following output: f1(T2, T1)
f1(T1, T2)

16.2.2 Partial Ordering of Overloaded Function
Templates
Reconsider our earlier example: We found that after substituting the given
template argument lists ( and ), overload resolution ended up
selecting the right function to call: Click here to view code image
std::cout << f((int*)nullptr); // calls f(T)
std::cout << f((int*)nullptr); // calls f(T*)

However, a function is selected even when explicit template arguments are not
provided. In this case, template argument deduction comes into play. Let’s
slightly modify function main() in the previous example to discuss this
mechanism: Click here to view code image
details/funcoverload2.cpp
#include 
template
int f(T)
{
return 1;
}
template
int f(T*)
{
return 2;
}
int main()
{
std::cout << f(0); // calls f(T)
std::cout << f(nullptr); // calls f(T)
std::cout << f((int*)nullptr); // calls f(T*)
}

Consider the first call, f(0): The type of the argument is int, which matches
the type of the parameter of the first template if we substitute T with int.
However, the parameter type of the second template is always a pointer and,

hence, after deduction, only an instance generated from the first template is a
candidate for the call. In this case overload resolution is trivial.
The same applies to the second call: (f(nullptr): The type of the
argument is std::nullptr_t, which again only matches for the first
template.
The third call (f((int*)nullptr)) is more interesting: Argument
deduction succeeds for both templates, yielding the functions f
(int*) and f(int*). From a traditional overload resolution
perspective, both are equally good functions to call with an int* argument,
which would suggest that the call is ambiguous (see Appendix C). However, in
this sort of case, an additional overload resolution criterion comes into play: The
function generated from the more specialized template is selected. Here (as we
see shortly), the second template is considered more specialized and thus the
output of our example is 112

16.2.3 Formal Ordering Rules
In our last example, it may seem very intuitive that the second template is more
special than the first because the first can accommodate just about any argument
type, whereas the second allows only pointer types. However, other examples are
not necessarily as intuitive. In what follows, we describe the exact procedure to
determine whether one function template participating in an overload set is more
specialized than the other. Note that these are partial ordering rules: It is possible
that given two templates, neither can be considered more specialized than the
other. If overload resolution must select between two such templates, no decision
can be made, and the program contains an ambiguity error.
Let’s assume we are comparing two identically named function templates that
seem viable for a given function call. Overload resolution is decided as follows:
• Function call parameters that are covered by a default argument and ellipsis
parameters that are not used are ignored in what follows.
• We then synthesize two artificial lists of argument types (or for conversion
function templates, a return type) by substituting every template parameter as
follows: 1. Replace each template type parameter with a unique invented type.
2. Replace each template template parameter with a unique invented class
template.
3. Replace each nontype template parameter with a unique invented value of
the appropriate type. (Types, templates, and values that are invented in this

context are distinct from any other types, templates, or values that either the
programmer used or the compiler synthesized in other contexts.) • If template
argument deduction of the second template against the first synthesized list of
argument types succeeds with an exact match, but not vice versa, then the first
template is more specialized than the second. Conversely, if template argument
deduction of the first template against the second synthesized list of argument
types succeeds with an exact match, but not vice versa, then the second
template is more specialized than the first. Otherwise (either no deduction
succeeds or both succeed), there is no ordering between the two templates.
Let’s make this concrete by applying it to the two templates in our last
example. From these two templates, we synthesize two lists of argument types
by replacing the template parameters as described earlier: (A1) and (A2*)
(where A1 and A2 are unique made up types). Clearly, deduction of the first
template against the second list of argument types succeeds by substituting
A2* for T. However, there is no way to make T* of the second template match
the nonpointer type A1 in the first list. Hence, we formally conclude that the
second template is more specialized than the first.
Consider a more intricate example involving multiple function parameters:
Click here to view code image
template
void t(T*, T const* = nullptr, …);
template
void t(T const*, T*, T* = nullptr);
void example(int* p)
{
t(p, p);
}

First, because the actual call does not use the ellipsis parameter for the first
template and the last parameter of the second template is covered by its default
argument, these parameters are ignored in the partial ordering. Note that the
default argument of the first template is not used; hence the corresponding
parameter participates in the ordering.
The synthesized lists of argument types are (A1*, A1 const*) and (A2
const*, A2*). Template argument deduction of (A1*, A1 const*)
versus the second template actually succeeds with the substitution of T with A1
const, but the resulting match is not exact because a qualification adjustment is
needed to call t(A1 const*, A1 const*, A1 const*
= 0) with arguments of types (A1*, A1 const*). Similarly, no exact

match can be found by deducing template arguments for the first template from
the argument type list (A2 const*, A2*). Therefore, there is no ordering
relationship between the two templates, and the call is ambiguous.
The formal ordering rules generally result in the intuitive selection of function
templates. Once in a while, however, an example comes up for which the rules
do not select the intuitive choice. It is therefore possible that the rules will be
revised to accommodate those examples in the future.

16.2.4 Templates and Nontemplates
Function templates can be overloaded with nontemplate functions. All else being
equal, the non-template function is preferred in selecting the actual function
being called. The following example illustrates this:

details/nontmpl1.cpp
#include 
#include 
template
std::string f(T)
{

return "Template";
}
std::string f(int&)
{
return "Nontemplate";
}
int main()
{
int x = 7;
std::cout << f(x) << ’\n’;//prints: Nontemplate
}

This outputs
Nontemplate

However, when const and reference qualifiers differ, priorities for overload
resolution can change. For example: Click here to view code image
details/nontmpl2.cpp
#include 
#include 
template
std::string f(T&)
{
return "Template";
}
std::string f(int const&)
{
return "Nontemplate";
}
int main()
{
int x = 7;
std::cout << f(x) << ’\n’;//prints: Template
int const c = 7;
std::cout << f(c) << ’\n’;//prints: Nontemplate
}

The program has the following output: Template
Nontemplate
Now, the function template f<>(T&) is a better match when passing a

nonconstant int. The reason is that for an int the instantiated f<>(int&) is
a better match than f(int const&). Thus, the difference is not only the fact
that one function is a template and the other is not. In that case the general rules
of overload resolution apply (see Section C.2 on page 682). Only when calling
f() for a int const, do both signatures have the same type int const&,
so that the nontemplate is preferred.
For this reason, it’s a good idea to declare the member function template as
Click here to view code image
template
std::string f(T const&)
{
return "Template";
}

Nevertheless, this effect can easily occur accidentally and cause surprising
behavior when member functions are defined that accept the same arguments as
copy or move constructors. For example: Click here to view code image
details/tmplconstr.cpp
#include 
#include 
class C {
public:
C() = default;
C (C const&) {
std::cout << "copy constructor\n";
}
C (C&&) {
std::cout << "move constructor\n";
}
template
C (T&&) {
std::cout << "template constructor\n";
}
};
int main()
{
C x;
C x2{x}; // prints:
C x3{std::move(x)};
C const c;
C x4{c}; // prints:
C x5{std::move(c)};
}

template constructor
// prints: move constructor
copy constructor
// prints: template constructor

The program has the following output: template constructor
move constructor
copy constructor
template constructor Thus, the member function template is a better match for
copying a C than the copy constructor. And for std::move(c), which yields
type C const&& (a type that is possible but usually doesn’t have meaningful
semantics), the member function template also is a better match than the move
constructor.
For this reason, usually you have to partially disable such member function
templates when they might hide copy or move constructors. This is explained in
Section 6.4 on page 99.

16.2.5 Variadic Function Templates
Variadic function templates (see Section 12.4 on page 200) require some special
treatment during partial ordering, because deduction for a parameter pack
(described in Section 15.5 on page 275) matches a single parameter to multiple
arguments. This behavior introduces several interesting situations for function
template ordering, illustrated by the following example: Click here to view code
image
details/variadicoverload.cpp
#include 
template
int f(T*)
{
return 1;
}
template
int f(Ts…)
{
return 2;
}
template
int f(Ts*…)
{
return 3;
}
int main()

{
std::cout << f(0, 0.0); // calls f<>(Ts…)
std::cout << f((int*)nullptr, (double*)nullptr); // calls f<>(Ts*…)
std::cout << f((int*)nullptr); // calls f<>(T*)
}

The output of this example, which we will discuss in a moment, is 231
In the first call, f(0, 0.0), each of the function templates named f is
considered. For the first function template, f(T*), deduction fails both because
the template parameter T cannot be deduced and because there are more function
arguments than parameters for this nonvariadic function template. The second
function template, f(Ts…), is variadic: Deduction in this case compares the
pattern of a function parameter pack (Ts) against against the types of the two
arguments (int and double, respectively), deducing Ts to the sequence (int,
double). For the third function template, f(Ts*…), deduction compares the
pattern of the function parameter pack Ts* against each of the argument types.
This deduction fails (Ts cannot be deduced), leaving only the second function
template viable. Function template ordering is not required.
The second call, f((int*)nullptr, (double*)nullptr), is more
interesting: Deduction fails for the first function template because there are more
function arguments than parameters, but deduction succeeds for the second and
third templates. Written explicitly, the resulting calls would be Click here to
view code image
f((int*)nullptr, (double*)nullptr) //for second
template

and
Click here to view code image
f((int*)nullptr, (double*)nullptr) //for third template

Partial ordering then considers the second and third templates, both of which are
variadic as follows: When applying the formal ordering rules described in
Section 16.2.3 on page 331 to a variadic template, each template parameter pack
is replaced by a single made-up type, class template, or value. For example, this
means that the synthesized argument types for the second and third function
templates are A1 and A2*, respectively, where A1 and A2 are unique, made-up
types. Deduction of the second template against the third’s list of argument types
succeeds by substituting the single-element sequence (A2*) for the parameter
pack Ts. However, there is no way to make the pattern Ts* of the third

template’s parameter pack match the nonpointer type A1, so the third function
template (which accepts pointer arguments) is considered more specialized than
the second function template (which accepts any arguments).
The third call, f((int*)nullptr), introduces a new wrinkle: Deduction
succeeds for all three of the function templates, requiring partial ordering to
compare a nonvariadic template to a variadic template. To illustrate, we compare
the first and third function templates. Here, the synthesized argument types are
A1* and A2*, where A1 and A2 are unique, made-up types. Deduction of the
first template against the third’s synthesized argument list would normally
succeed by substituting A2 for T. In the other direction, deduction of the third
template against the first’s synthesized argument list succeeds by substituting the
single-element sequence (A1) for the parameter pack Ts. Partial ordering
between the first and third templates would normally result in an ambiguity.
However, a special rule prohibits an argument that originally came from a
function parameter pack (e.g., the third template’s parameter pack Ts*…) from
matching a parameter that is not a parameter pack (the first template’s parameter
T *). Hence, template deduction of the first template against the third’s
synthesized argument list fails, and the first template is considered more
specialized than the third. This special rule effectively considers nonvariadic
templates (those with a fixed number of parameters) to be more specialized than
variadic templates (with a variable number of parameters).
The rules described above apply equally to pack expansions that occur in
types in the function signature. For example, we can wrap the parameters and
arguments of each of the function templates in our previous example into a
variadic class template Tuple to arrive at a similar example not involving
function parameter packs: Click here to view code image
details/tupleoverload.cpp
#include 
template class Tuple
{
};
template
int f(Tuple)
{
return 1;
}
template

int f(Tuple)
{
return 2;
}
template
int f(Tuple)
{
return 3;
}
int main()
{
std::cout << f(Tuple()); // calls f<>(Tuple)
std::cout << f(Tuple()); // calls f<>(Tuple)
std::cout << f(Tuple()); // calls f<>(Tuple)
}

Function template ordering considers the pack expansions in the template
arguments to Tuple analogously to the function parameter packs in our
previous example, resulting in the same output: 231

16.3 Explicit Specialization
The ability to overload function templates, combined with the partial ordering
rules to select the “best” matching function template, allows us to add more
specialized templates to a generic implementation to tune code transparently for
greater efficiency. However, class templates and variable templates cannot be
overloaded. Instead, another mechanism was chosen to enable transparent
customization of class templates: explicit specialization. The standard term
explicit specialization refers to a language feature that we call full specialization
instead. It provides an implementation for a template with template parameters
that are fully substituted: No template parameters remain. Class templates,
function templates, and variable templates can be fully specialized.2
So can members of class templates that may be defined outside the body of a
class definition (i.e., member functions, nested classes, static data members, and
member enumeration types).
In a later section, we will describe partial specialization. This is similar to full
specialization, but instead of fully substituting the template parameters, some
parameterization is left in the alternative implementation of a template. Full
specializations and partial specializations are both equally “explicit” in our
source code, which is why we avoid the term explicit specialization in our

discussion. Neither full nor partial specialization introduces a totally new
template or template instance. Instead, these constructs provide alternative
definitions for instances that are already implicitly declared in the generic (or
unspecialized) template. This is a relatively important conceptual observation,
and it is a key difference with overloaded templates.

16.3.1 Full Class Template Specialization
A full specialization is introduced with a sequence of three tokens: template,
<, and >.3 In addition, the class name is followed by the template arguments
for which the specialization is declared. The following example illustrates this:
Click here to view code image
template
class S {
public:
void info() {
std::cout << "generic (S::info())\n";
}
};
template<>
class S {
public:
void msg() {
std::cout << "fully specialized (S::msg())\n";
}
};

Note how the implementation of the full specialization does not need to be
related in any way to the generic definition: This allows us to have member
functions of different names (info versus msg). The connection is solely
determined by the name of the class template.
The list of specified template arguments must correspond to the list of
template parameters. For example, it is not valid to specify a nontype value for a
template type parameter. However, template arguments for parameters with
default template arguments are optional: template class Types {
public:
using I = int;
};
template::I>

class S; //#1
template<>
class S { // #2
public:
void f();
};
template<> class S; // #3
template<> class S; // ERROR: 0 cannot substitute U
int main()
{
S* pi; // OK: uses #1 , no definition needed
S e1; // ERROR: uses #1 , but no definition available
S* pv; // OK: uses #2
S sv; // OK: uses #2 , definition available
S e2; // ERROR: uses #1 , but no definition available
S e3; // ERROR: uses #3 , but no definition available
}
template<>
class S { //definition for #3
};
As this example also shows, declarations of full specializations (and of
templates) do not necessarily have to be definitions. However, when a full
specialization is declared, the generic definition is never used for the given set of
template arguments. Hence, if a definition is needed but none is provided, the
program is in error. For class template specialization, it is sometimes useful to
“forward declare” types so that mutually dependent types can be constructed. A
full specialization declaration is identical to a normal class declaration in this
way (it is not a template declaration). The only differences are the syntax and the
fact that the declaration must match a previous template declaration. Because it
is not a template declaration, the members of a full class template specialization
can be defined using the ordinary out-of-class member definition syntax (in
other words, the template<> prefix cannot be specified): Click here to view
code image

template
class S;
template<> class S {
public:
void print() const;
};
// the following definition cannot be preceded by template<>
void S::print() const
{
std::cout << "pointer to pointer to char\n";
}

A more complex example may reinforce this notion:
Click here to view code image
template
class Outside {
public: template
class Inside {
}; };
template<>
class Outside {
// there is no special connection between the following nested class
// and the one defined in the generic template
template
class Inside {
private:
static int count;
};
};
// the following definition cannot be preceded by template<>
template
int Outside::Inside::count = 1;

A full specialization is a replacement for the instantiation of a certain generic
template, and it is not valid to have both the explicit and the generated versions
of a template present in the same program. An attempt to use both in the same
file is usually caught by a compiler: Click here to view code image
template
class Invalid {
};
Invalid x1; // causes the instantiation of Invalid
template<>
class Invalid; // ERROR: Invalid already instantiated

Unfortunately, if the uses occur in different translation units, the problem may

not be caught so easily. The following invalid C++ example consists of two files
and compiles and links on many implementations, but it is invalid and
dangerous: Click here to view code image
// Translation unit 1:
template
class Danger {
public:
enum { max = 10 };
};
char buffer[Danger ::max]; // uses generic value
extern void clear(char*);
int main()
{
clear(buffer);
}
// Translation unit 2:
template
class Danger;
template<>
class Danger {
public:
enum { max = 100 };
};
void clear(char* buf)
{
// mismatch in array bound:
for (int k = 0; k ::max; ++k) {
buf[k] = ’\0’;
}
}

This example is clearly contrived to keep it short, but it illustrates that care must
be taken to ensure that the declaration of the specialization is visible to all the
users of the generic template. In practical terms, this means that a declaration of
the specialization should normally follow the declaration of the template in its
header file. When the generic implementation comes from an external source
(such that the corresponding header files should not be modified), this is not
necessarily practical, but it may be worth creating a header including the generic
template followed by declarations of the specializations to avoid these hard-tofind errors. We find that, in general, it is better to avoid specializing templates
coming from an external source unless it is clearly marked as being designed for
that purpose.

16.3.2 Full Function Template Specialization
The syntax and principles behind (explicit) full function template specialization
are much the same as those for full class template specialization, but overloading
and argument deduction come into play.
The full specialization declaration can omit explicit template arguments when
the template being specialized can be determined via argument deduction (using
as argument types the parameter types provided in the declaration) and partial
ordering. For example: Click here to view code image
template
int f(T) // #1
{
return 1;
}
template
int f(T*) // #2
{
return 2;
}
template<> int f(int) // OK: specialization of #1
{
return 3;
}
template<> int f(int*) // OK: specialization of #2
{
return 4;
}

A full function template specialization cannot include default argument values.
However, any default arguments that were specified for the template being
specialized remain applicable to the explicit specialization: Click here to view
code image
template
int f(T, T x = 42)
{
return x;
}
template<> int f(int, int = 35) // ERROR
{
return 0;
}

(That’s because a full specialization provides an alternative definition, but not an

alternative declaration. At the point of a call to a function template, the call is
entirely resolved based on the function template.) A full specialization is in
many ways similar to a normal declaration (or rather, a normal redeclaration). In
particular, it does not declare a template, and therefore only one definition of a
noninline full function template specialization should appear in a program.
However, we must still ensure that a declaration of the full specialization
follows the template to prevent attempts at using the function generated from the
template. The declarations for a template g() and one full specialization would
therefore typically be organized in two files as follows: • The interface file
contains the definitions of primary templates and partial specializations but
declares only the full specializations: Click here to view code image
#ifndef TEMPLATE_G_HPP
#define TEMPLATE_G_HPP
// template definition should appear in header file:
template
int g(T, T x = 42)
{
return x;
}
// specialization declaration inhibits instantiations of the
template;
// definition should not appear here to avoid multiple definition
errors
template<> int g(int, int y);
#endif // TEMPLATE_G_HPP

• The corresponding implementation file defines the full specialization: Click
here to view code image
#include "template_g.hpp"
template<> int g(int, int y)
{
return y/2;
}

Alternatively, the specialization could be made inline, in which case its
definition can be (and should be) placed in the header file.

16.3.3 Full Variable Template Specialization

Variable templates can also be fully specialized. By now, the syntax should be
intuitive: Click here to view code image
template constexpr std::size_t SZ = sizeof(T);
template<> constexpr std::size_t SZ = 0; Clearly, the
specialization can provide an initializer that is distinct from that
resulting from the template. Interestingly, a variable template
specialization is not required to have a type matching that of the
template being specialized: Click here to view code image
template typename T::iterator null_iterator;
template<> BitIterator null_iterator>;
// BitIterator doesn’t match T::iterator, and that is fine

16.3.4 Full Member Specialization
Not only member templates, but also ordinary static data members and member
functions of class templates, can be fully specialized. The syntax requires
template<> prefix for every enclosing class template. If a member template is
being specialized, a template<> must also be added to denote that it is being
specialized. To illustrate the implications of this, let’s assume the following
declarations: Click here to view code image
template
class Outer { // #1
public:
template
class Inner { // #2
private:
static int count; // #3
};
static int code; // #4
void print() const { // #5
std::cout << "generic";
}
};
template
int Outer::code = 6; // #6
template template
int Outer::Inner::count = 7; // #7
template<>
class Outer { // #8
public:
template
class Inner { // #9
private:

static int count; //#10
};
void print() const { //#11
}
};

The ordinary members code at point #4 and print() at point #5 of the
generic Outer template #1 have a single enclosing class template and hence
need one template<> prefix to specialize them fully for a specific set of
template arguments: Click here to view code image
template<>
int Outer::code = 12;
template<>
void Outer::print() const
{
std::cout << "Outer";
}

These definitions are used over the generic ones at points #4 and #5 for class
Outer, but other members of class Outer are still generated
from the template at point #1 . Note that after these declarations, it is no longer
valid to provide an explicit specialization for Outer.
Just as with full function template specializations, we need a way to declare
the specialization of an ordinary member of a class template without specifying a
definition (to prevent multiple definitions). Although nondefining out-of-class
declarations are not allowed in C++ for member functions and static data
members of ordinary classes, they are fine when specializing members of class
templates. The previous definitions could be declared with Click here to view
code image
template<>
int Outer::code;
template<>
void Outer::print() const; The attentive reader might point out
that the nondefining declaration of the full specialization of
Outer::code looks exactly like a definition to be initialized
with a default constructor. This is indeed so, but such declarations
are always interpreted as nondefining declarations. For a full
specialization of a static data member with a type that can only be
initialized using a default constructor, we must resort to
initializer list syntax. Given the following: Click here to view code
image
class DefaultInitOnly {
public:
DefaultInitOnly() = default;

DefaultInitOnly(DefaultInitOnly const&) = delete;
};
template
class Statics {
private:
static T sm;
};

the following is a declaration:
Click here to view code image
template<>
DefaultInitOnly Statics::sm;

while the following is a definition that calls the default constructor: Click here to
view code image
template<>
DefaultInitOnly Statics::sm{}; Prior to C++11, this
was not possible. Default initialization was thus not available for
such specializations. Typically, an initializer copying a default
value was used: Click here to view code image
template<>
DefaultInitOnly Statics::sm = DefaultInitOnly();

Unfortunately, for our example that was not possible because the copy
constructor is deleted. However, C++17 introduced mandatory copy-elision
rules, which make that alternative valid, because no copy constructor invocation
is involved anymore.
The member template Outer::Inner can also be specialized for a
given template argument without affecting the other members of the specific
instantiation of Outer, for which we are specializing the member template.
Again, because there is one enclosing template, we will need one template<>
prefix. This results in code like the following: Click here to view code image
template<>
template
class Outer::Inner {
public:
static long count; // member type changed
};
template<>
template
long Outer::Inner::count; The template Outer::Inner
can also be fully specialized, but only for a given instance of
Outer. We now need two template<> prefixes: one because of the
enclosing class and one because we’re fully specializing the (inner)

template: Click here to view code image
template<>
template<>
class Outer::Inner {
public:
enum { count = 1 };
};
// the following is not valid C++:
// template<> cannot follow a template parameter list
template
template<> class Outer::Inner; // ERROR

Contrast this with the specialization of the member template of Outer.
Because the latter is already fully specialized, there is no enclosing template, and
we need only one template<> prefix: Click here to view code image
template<>
class Outer::Inner {
public:
enum { count = 2 };
};

16.4 Partial Class Template Specialization
Full template specialization is often useful, but sometimes it is natural to want to
specialize a class template or variable template for a family of template
arguments rather than just one specific set of template arguments. For example,
let’s assume we have a class template implementing a linked list: Click here to
view code image
template
class List { // #1
public:
…
void append(T const&);
inline std::size_t length() const;
…
};

A large project making use of this template may instantiate its members for
many types. For member functions that are not expanded inline (say,
List::append()), this may cause noticeable growth in the object code.
However, we may know that from a low-level point of view, the code for
List::append() and List::append() is the same.

In other words, we’d like to specify that all Lists of pointers share an
implementation. Although this cannot be expressed in C++, we can achieve
something quite close by specifying that all Lists of pointers should be
instantiated from a different template definition: Click here to view code image
template
class List { // #2
private:
List impl;
…
public:
…
inline void append(T* p) {
impl.append(p);
}
inline std::size_t length() const {
return impl.length();
}
…
};

In this context, the original template at point #1 is called the primary template,
and the latter definition is called a partial specialization (because the template
arguments for which this template definition must be used have been only
partially specified). The syntax that characterizes a partial specialization is the
combination of a template parameter list declaration (template<… >) and a
set of explicitly specified template arguments on the name of the class template
( in our example).
Our code contains a problem because List recursively contains a
member of that same List type. To break the cycle, we can precede
the previous partial specialization with a full specialization: Click here to view
code image
template<>
class List { // #3
…
void append (void* p);
inline std::size_t length() const;
…
};

This works because matching full specializations are preferred over partial
specializations. As a result, all member functions of Lists of pointers are
forwarded (through easily inlineable functions) to the implementation of
List. This is an effective way to combat code bloat (of which C++
templates are often accused).

There exist several limitations on the parameter and argument lists of partial
specialization declarations. Some of them are as follows: 1. The arguments of
the partial specialization must match in kind (type, nontype, or template) the
corresponding parameters of the primary template.
2. The parameter list of the partial specialization cannot have default arguments;
the default arguments of the primary class template are used instead.
3. The nontype arguments of the partial specialization should be either
nondependent values or plain nontype template parameters. They cannot be
more complex dependent expressions like 2*N (where N is a template
parameter).
4. The list of template arguments of the partial specialization should not be
identical (ignoring renaming) to the list of parameters of the primary template.
5. If one of the template arguments is a pack expansion, it must come at the end
of a template argument list.
An example illustrates these limitations:
Click here to view code image
template
class S; // primary template
template
class S; // ERROR: parameter kind mismatch
template
class S; // ERROR: no default arguments
template
class S; // ERROR: no nontype expressions
template
class S; // ERROR: no significant difference from primary
template
template
class Tuple;
template
class Tuple; // ERROR: pack expansion not at the end
template
class Tuple, Tail>; // OK: pack expansion is at the end of
a
// nested template argument list

Every partial specialization—like every full specialization—is associated with
the primary template. When a template is used, the primary template is always

the one that is looked up, but then the arguments are also matched against those
of the associated specializations (using template argument deduction, as
described in Chapter 15) to determine which template implementation is picked.
Just as with function template argument deduction, the SFINAE principle applies
here: If, while attempting to match a partial specialization an invalid construct is
formed, that specialization is silently abandoned and another candidate is
examined if one is available. If no matching specializations is found, the primary
template is selected. If multiple matching specializations are found, the most
specialized one (in the sense defined for overloaded function templates) is
selected; if none can be called most specialized, the program contains an
ambiguity error.
Finally, we should point out that it is entirely possible for a class template
partial specialization to have more or fewer parameters than the primary
template. Consider our generic template List, declared at point #1 , again. We
have already discussed how to optimize the list-of-pointers case, but we may
want to do the same with certain pointer-to-member types. The following code
achieves this for pointer-to-member-pointers: Click here to view code image
// partial specialization for any pointer-to-void* member
template
class List { // #4
public:
using ElementType = void* C::*;
…
void append(ElementType pm);
inline std::size_t length() const;
…
};
// partial specialization for any pointer-to-member-pointer type
except
// pointer-to-void* member, which is handled earlier
// (note that this partial specialization has two template
parameters,
// whereas the primary template only has one parameter)
// this specialization makes use of the prior one to achieve the
// desired optimization
template
class List { // #5
private:
List impl;
…
public:
using ElementType = T* C::*;
…
inline void append(ElementType pm) {
impl.append((void* C::*)pm);

}
inline std::size_t length() const {
return impl.length();
}
…
};

In addition to our observation regarding the number of template parameters, note
that the common implementation defined at #4 to which all others are forwarded
by the declaration at point #5 is itself a partial specialization (for the simple
pointer case it is a full specialization). However, it is clear that the specialization
at point #4 is more specialized than that at point #5 ; thus no ambiguity should
occur.
Moreover, it is even possible that the number of explicitly written template
arguments can differ from the number of template parameters in the primary
template. This can happen both with default template arguments and, in a far
more useful manner, with variadic templates: Click here to view code image
template
class Tuple; // primary template
template
class Tuple; // one-element tuple
template
class Tuple; // tuple with two or more elements

16.5 Partial Variable Template Specialization
When variable templates were added to the draft C++11 standard, several
aspects of their specifications were overlooked, and some of those issues have
still not been formally resolved. However, actual implementations generally
agree on the handling of these issues.
Perhaps the most surprising of these issues is that the standard refers to the
ability to partially specialize variable templates, but it does not describe how
they are declared or what they mean. What follows is thus based on C++
implementations in practice (which do permit such partial specializations), and
not on the C++ standard.
As one would expect, the syntax is similar to full variable template
specialization, except that template<> is replaced by an actual template
declaration header, and the template argument list following the variable

template name must depend on template parameters. For example: Click here to
view code image
template constexpr std::size_t SZ = sizeof(T);
template constexpr std::size_t SZ = sizeof(void*); As
with the full specialization of variable templates, the type of a
partial specialization is not required to match that of the primary
template: Click here to view code image
template typename T::iterator null_iterator;
template T* null_iterator =
null_ptr;
// T* doesn’t match T::iterator, and that is fine

The rules regarding the kinds of template arguments that can be specified for a
variable template partial specialization are identical to those for class template
specializations. Similarly, the rules to select a specialization for a given list of
concrete template arguments are identical too.

16.6 Afternotes
Full template specialization was part of the C++ template mechanism from the
start. Function template overloading and class template partial specialization, on
the other hand, came much later. The HP aC++ compiler was the first to
implement function template overloading, and EDG’s C++ front end was the
first to implement class template partial specialization. The partial ordering
principles described in this chapter were originally invented by Steve Adamczyk
and John Spicer (who are both of EDG).
The ability of template specializations to terminate an otherwise infinitely
recursive template definition (such as the List example presented in
Section 16.4 on page 348) was known for a long time. However, Erwin Unruh
was perhaps the first to note that this could lead to the interesting notion of
template metaprogramming: using the template instantiation mechanism to
perform nontrivial computations at compile time. We devote Chapter 23 to this
topic.
You may legitimately wonder why only class templates and variable templates
can be partially specialized. The reasons are mostly historical. It is probably
possible to define the same mechanism for function templates (see Chapter 17).
In some ways, the effect of overloading function templates is similar, but there
are also some subtle differences. These differences are mostly related to the fact

that only the primary template needs to be looked up when a use is encountered.
The specializations are considered only afterward, to determine which
implementation should be used. In contrast, all overloaded function templates
must be brought into an overload set by looking them up, and they may come
from different namespaces or classes. This increases the likelihood of
unintentionally overloading a template name somewhat.
Conversely, it is also imaginable to allow a form of overloading of class
templates and variable templates. Here is an example: Click here to view code
image
// invalid overloading of class templates
template class Pair;
template class Pair; However, there doesn’t seem to
be a pressing need for such a mechanism.
1

This definition differs from that given in the C++ standard, but its
consequences are equivalent.
2 Alias templates are the only form of template that cannot be specialized,
either by a full specialization or a partial specialization. This restriction is
necessary to make the use of template aliases transparent to the template
argument deduction process Section 15.11 on page 312.
3 The same prefix is also needed to declare full function template
specializations. Earlier designs of the C++ language did not include this
prefix, but the addition of member templates required additional syntax to
disambiguate complex specialization cases.

Chapter 17
Future Directions
C++ templates have been evolving almost continuously from their initial design
in 1988, through the various standardization milestones in 1998, 2011, 2014, and
2017. It could be argued that templates were at least somewhat related to most
major language additions after the original 1998 standard.
The first edition of this book listed a number of extensions that we might see
after the first standard, and several of those became reality: • The angle bracket
hack: C++11 removed the need to insert a space between two closing angle
brackets.
• Default function template arguments: C++11 allows function templates to have
default template arguments.
• Typedef templates: C++11 introduced alias templates, which are similar.
• The typeof operator: C++11 introduced the decltype operator, which fills
the same role (but uses a different token to avoid a conflict with an existing
extension that doesn’t quite meet the needs of the C++ programmers’
community).
• Static properties: The first edition anticipated a selection of type traits being
supported directly by compilers. This has come to pass, although the interface
is expressed using the standard library (which is then implemented using
compiler extensions for many of the traits).
• Custom instantiation diagnostics: The new keyword static_assert
implements the idea described by std::instantiation_error in the
first edition of this book.
• List parameters: This became parameter packs in C++11.
• Layout control: C++11’s alignof and alignas cover the needs described
in the first edition. Furthermore, the C++17 library added a std::variant
template to support discriminated unions.
• Initializer deduction: C++17 added class template argument deduction, which
addresses the same issue.
• Function expressions: C++11’s lambda expressions provides exactly this
functionality (with a syntax somewhat different from that discussed in the first

edition).
Other directions hypothesized in the first edition have not made it into the
modern language, but most are still discussed on occasion and we keep their
presentation in this volume. Meanwhile, other ideas are emerging and we present
some of those as well.

17.1 Relaxed typename Rules
In the first edition of this book, this section suggested that the future might bring
two kinds of relaxations to the rules for the use of typename (see Section
13.3.2 on page 228): Allow typename where it was not previously allowed,
and make typename optional where a compiler can relatively easily infer that a
qualified name with a dependent qualifier must name a type. The former came to
pass (typename in C++11 can be used redundantly in many places), but the
latter has not.
Recently, however, there has been a renewed call to make typename
optional in various common contexts where the expectation of a type specifier is
unambiguous: • The return type and parameter types of function and member
function declarations in namespace and class scope. Similarly with function and
member function templates and with lambda expressions appearing in any scope.
• The types of variable, variable template, and static data member declarations.
Again, similarly with variable templates.
• The type after the = token in an alias or alias template declaration.
• The default argument of a type parameter of a template.
• The type appearing in the angle brackets following a static_cast,
const_cast, dynamic_cast, or reinterpret_cast, construct.
• The type named in a new expression.
Although this is a relatively ad hoc list, it turns out that such a change in the
language would allow by far most instances of this use of typename to be
dropped, which would make code more compact and more readable.

17.2 Generalized Nontype Template Parameters
Among the restrictions on nontype template arguments, perhaps the most
surprising to beginning and advanced template writers alike is the inability to

provide a string literal as a template argument.
The following example seems intuitive enough: Click here to view code
image
template
class Diagnoser {
public:
void print();
};
int main()
{
Diagnoser<"Surprise!">().print();
}

However, there are some potential problems. In standard C++, two instances of
Diagnoser are the same type if and only if they have the same arguments. In
this case the argument is a pointer value—in other words, an address. However,
two identical string literals appearing in different source locations are not
required to have the same address. We could thus find ourselves in the awkward
situation that Diagnoser<"X"> and Diagnoser<"X"> are in fact two
different and incompatible types! (Note that the type of "X" is char
const[2], but it decays to char const* when passed as a template
argument.) Because of these (and related) considerations, the C++ standard
prohibits string literals as arguments to templates. However, some
implementations do offer the facility as an extension. They enable this by using
the actual string literal contents in the internal representation of the template
instance. Although this is clearly feasible, some C++ language commentators
feel that a nontype template parameter that can be substituted by a string literal
value should be declared differently from one that can be substituted by an
address. One possibility would be to capture string literals in a parameter pack of
characters. For example: Click here to view code image
template
class Diagnoser {
public:
void print();
};
int main()
{
// instantiates Diagnoser<’S’,’u’,’r’,’p’,’r’,’i’,’s’,’e’,’!’>
Diagnoser<"Surprise!">().print();
}

We should also note an additional technical wrinkle in this issue. Consider the

following template declarations, and let’s assume that the language has been
extended to accept string literals as template arguments in this case: Click here to
view code image
template
class Bracket {
public:
static char const* address();
static char const* bytes();
};
template
char const* Bracket::address()
{
return str;
}
template
char const* Bracket::bytes()
{
return str;
}

In the previous code, the two member functions are identical except for their
names—a situation that is not that uncommon. Imagine that an implementation
would instantiate Bracket<"X"> using a process much like macro expansion:
In this case, if the two member functions are instantiated in different translation
units, they may return different values. Interestingly, a test of some C++
compilers that currently provide this extension reveals that they do suffer from
this surprising behavior.
A related issue is the ability to provide floating-point literals (and simple
constant floating-point expressions) as template arguments. For example: Click
here to view code image
template
class Converter {
public:
static double convert (double val) {
return val*Ratio;
}
};
using InchToMeter = Converter<0.0254>; This too is provided by some
C++ implementations and presents no serious technical challenges
(unlike the string literal arguments).

C++11 introduced a notion of a literal class type: a class type that can take
constant values computed at compile time (including nontrivial computations
through constexpr functions). Once such class types became available, it

quickly became desirable to allow them for nontype template parameters.
However, problems similar to those of the string literal parameters described
above arose. In particular, the “equality” of two class-type values is not a trivial
matter, because it is in general determined by operator== definitions. This
equality determines if two instantiations are equivalent, but in practice, that
equivalence must be checkable by the linker by comparing mangled names. One
way out may be an option to mark certain literal classes as having a trivial
equality criterion that amounts to pairwise comparing of the scalar members of
the class. Only class types with such a trivial equality criterion would then be
permitted as nontype template parameter types.

17.3 Partial Specialization of Function Templates
In Chapter 16 we discussed how class templates can be partially specialized,
whereas function templates are simply overloaded. The two mechanisms are
somewhat different.
Partial specialization doesn’t introduce a completely new template: It is an
extension of an existing template (the primary template). When a class template
is looked up, only primary templates are considered at first. If, after the selection
of a primary template, it turns out that there is a partial specialization of that
template with a template argument pattern that matches that of the instantiation,
its definition (in other words, its body) is instantiated instead of the definition of
the primary template. (Full template specializations work exactly the same way.)
In contrast, overloaded function templates are separate templates that are
completely independent of one another. When selecting which template to
instantiate, all the overloaded templates are considered together, and overload
resolution attempts to choose one as the best fit. At first this might seem like an
adequate alternative, but in practice there are a number of limitations: • It is
possible to specialize member templates of a class without changing the
definition of that class. However, adding an overloaded member does require a
change in the definition of a class. In many cases this is not an option because
we may not own the rights to do so. Furthermore, the C++ standard does not
currently allow us to add new templates to the std namespace, but it does allow
us to specialize templates from that namespace.
• To overload function templates, their function parameters must differ in some
material way. Consider a function template R convert(T const&) where
R and T are template parameters. We may very well want to specialize this

template for R = void, but this cannot be done using overloading.
• Code that is valid for a nonoverloaded function may no longer be valid when
the function is overloaded. Specifically, given two function templates f(T)
and g(T) (where T is a template parameter), the expression g(&f) is
valid only if f is not overloaded (otherwise, there is no way to decide which f
is meant).
• Friend declarations refer to a specific function template or an instantiation of a
specific function template. An overloaded version of a function template would
not automatically have the privileges granted to the original template.
Together, this list forms a compelling argument in support of a partial
specialization construct for function templates.
A natural syntax for partially specializing function templates is the
generalization of the class template notation: Click here to view code image
template
T const& max (T const&, T const&); // primary template
template
T* const& max (T* const&, T* const&); // partial specialization

Some language designers worry about the interaction of this partial
specialization approach with function template overloading. For example: Click
here to view code image
template
void add (T& x, int i); // a primary template
template
void add (T1 a, T2 b); // another (overloaded) primary template
template
void add (T*&, int); // Which primary template does this
specialize?

However, we expect such cases would be deemed errors without major impact
on the utility of the feature.
This extension was briefly discussed during the standardization of C++11 but
gathered relatively little interest in the end. Still, the topic occasionally arises
because it neatly solves some common programming problems. Perhaps it will
be taken up again in some future version of the C++ standard.

17.4 Named Template Arguments

Section 21.4 on page 512 describes a technique that allows us to provide a
nondefault template argument for a specific parameter without having to specify
other template arguments for which a default value is available. Although it is an
interesting technique, it is also clear that it results in a fair amount of work for a
relatively simple effect. Hence, providing a language mechanism to name
template arguments is a natural thought.
We should note at this point that a similar extension (sometimes called
keyword arguments) was proposed earlier in the C++ standardization process by
Roland Hartinger (see Section 6.5.1 of [StroustrupDnE]). Although technically
sound, the proposal was ultimately not accepted into the language for various
reasons. At this point there is no reason to believe named template arguments
will ever make it into the language, but the topic arises regularly in committee
discussions.
However, for the sake of completeness, we mention one syntactic idea that has
been discussed: Click here to view code image
template,
typename Copy = defaultCopy,
typename Swap = defaultSwap,
typename Init = defaultInit,
typename Kill = defaultKill>
class Mutator {
…
};
void test(MatrixList ml)
{
mySort (ml, Mutator );
}

Here, the period preceding the argument name is used to indicate that we’re
referring to a template argument by name. This syntax is similar to the
“designated initializer” syntax introduced in the 1999 C standard: Click here to
view code image
struct Rectangle { int top, left, width, height; };
struct Rectangle r = { .width = 10, .height = 10, .top = 0, .left = 0
}; Of course, introducing named template arguments means that the
template parameter names of a template are now part of the public
interface to that template and cannot be freely changed. This could
be addressed by a more explicit, opt-in syntax, such as the
following: Click here to view code image
template,
Copy: typename C = defaultCopy,

Swap:
Init:
Kill:
class
…
};

typename S = defaultSwap,
typename I = defaultInit,
typename K = defaultKill>
Mutator {

void test(MatrixList ml)
{
mySort (ml, Mutator );
}

17.5 Overloaded Class Templates
It is entirely possible to imagine that class templates could be overloaded on
their template parameters. For example, one can imagine creating a family of
Array templates that contains both dynamically and statically sized arrays:
Click here to view code image
template
class Array {
// dynamically sized array
…
};
template
class Array {
// fixed size array
…
};

The overloading isn’t necessarily restricted to the number of template
parameters; the kind of parameters can be varied too: Click here to view code
image
template
class Pair {
// pair of fields
…
};
template
class Pair {
// pair of constant integer values
…
};

Although this idea has been discussed informally by some language designers, it

has not yet been formally presented to the C++ standardization committee.

17.6 Deduction for Nonfinal Pack Expansions
Template argument deduction for pack expansions only works when the pack
expansion occurs at the end of the parameter or argument list. This means that
while it is fairly simple to extract the first element from a list: Click here to view
code image
template
struct Front;
template
struct Front {
using Type = FrontT;
};

one cannot easily extract the last element of the list due to the restrictions placed
on partial specializations described in Section 16.4 on page 347: Click here to
view code image
template
struct Back;
template
struct Back { //ERROR: pack expansion not at the end
of
using Type = BackT; // template argument list
};

Template argument deduction for variadic function templates is similarly
restricted. It is plausible that the rules regarding template argument deduction of
pack expansions and partial specializations will be relaxed to allow the pack
expansion to occur anywhere in the template argument list, making this kind of
operation far simpler. Moreover, it is possible—albeit less likely—that deduction
could permit multiple pack expansions within the same parameter list: Click here
to view code image
template class Tuple {
};
template
struct Split;
template
struct Split {

using before = Tuple;
using after = Tuple;
};

Allowing multiple pack expansions introduces additional complexity. For
example, does Split separate at the first occurrence of T, the last occurrence,
or one in between? How complicated can the deduction process become before
the compiler is permitted to give up?

17.7 Regularization of void
When programming templates, regularity is a virtue: If a single construct can
cover all cases, it makes our template simpler. One aspect of our programs that is
somewhat irregular are types. For example, consider the following: Click here to
view code image
auto&& r = f(); // error if f() returns void

That works for just about any type that f() returns except void. The same
problem occurs when using decltype(auto): Click here to view code image
decltype(auto) r = f(); // error if f() returns void

void is not the only irregular type: Function types and reference types often
also exhibit behaviors that make them exceptional in some way. However, it
turns out that void often complicates our templates and that there is no deep
reason for void to be unusual that way. For example, see Section 11.1.3 on
page 162 for an example how this complicates the implementation of a perfect
std::invoke() wrapper.
We could just decree that void is a normal value type with a unique value
(like std::nullptr_t for nullptr). For backward compatibility purposes,
we’d still have to keep a special case for function declarations like the following:
Click here to view code image
void g(void); // same as void g();

However, in most other ways, void would become a complete value type. We
could then for example declare void variables and references: void v = void{};
void&& rrv = f(); Most importantly, many templates would no longer need to be
specialized for the void case.

17.8 Type Checking for Templates
Much of the complexity of programming with templates comes from the
compiler’s inability to locally check whether a template definition is correct.
Instead, most of the checking of a template occurs during template instantiation,
when the template definition context and the template instantiation context are
intertwined. This mixing of different contexts makes it hard to assign blame:
Was the template definition at fault, because it used its template arguments
incorrectly, or was the template user at fault, because the supplied template
arguments didn’t meet the requirements of the template? The problem can be
illustrated with a simple example, which we have annotated with the diagnostics
produced by a typical compiler: Click here to view code image
template
T max(T a, T b)
{
return b < a ? a : b;
// ERROR: “no match for operator <
// (operator types are ’X’ and ’X’)”
}
struct X {
};
bool operator> (X, X);
int main()
{
X a, b;
X m = max(a, b); // NOTE: “in instantiation of function template
specialization
// ’max’ requested here”
}

Note that the actual error (the lack of a proper operator<) is detected within
the definition of the function template max(). It is possible that this is truly the
error—perhaps max() should have used operator> instead? However, the
compiler also provides a note that points to the place that caused the instantiation
of max, which may be the real error—perhaps max() is documented to
require operator requires LessThanComparable
T
max(T a, T b)
{
return b < a ? a : b;
}
struct X { };
bool operator> (X, X);
int main()
{
X a, b;
X m = max(a, b); // ERROR: X does not meet the LessThanComparable
requirement
}

By describing the requirements on the template parameter T, the compiler is able
to ensure that the function template max() only uses operations on T that the
user is expected to provide (in this case, LessThanComparable describes the
need for operator<). Moreover, when using a template, the compiler can
check that the supplied template argument provides all of the behavior required
for the max() function template to work properly. By separating the typechecking problem, it becomes far easier for the compiler to provide an accurate
diagnosis of the problem.
In the example above, LessThanComparable is called a concept: It
represents constraints on a type (in the more general case, constraints on a set of
types) that a compiler can check. Concept systems can be designed in different
ways.
During the standardization cycle for C++11, an elaborate system was fully
designed and implemented for concepts that are powerful enough to check both
the point of instantiation of a template and the definition of a template. The
former means, in our example above, that an error in main() could be caught
early with a diagnostic explaining that X doesn’t satisfy the constraints of
LessThanComparable. The latter means that when processing the max()
template, the compiler checks that no operation not permitted by the
LessThanComparable concept is used (and a diagnostic is emitted if that

constraint is violated). The C++11 proposal was eventually pulled from the
language specification because of various practical considerations (e.g., there
were still many minor specification issues whose resolution was threatening a
standard that was already running late).
After C++11 eventually shipped, a new proposal (first called concepts lite)
was presented and developed by members of the committee. This system does
not aim at checking the correctness of a template based on the constraints
attached to it. Instead it focuses on the point of instantiations only. So if in our
example max() were implemented using the > operator, no error would be
issued at that point. However, an error would still be issued in main() because
X doesn’t satisfy the constraints of LessThanComparable. The new
concepts proposal was implemented and specified in what is called the Concepts
TS (TS stands for Technical Specification), called C++ extensions for Concepts.1
Currently, the essential elements of that technical specification have been
integrated into the draft for the next standard (expected to become C++20).
Appendix E covers the language feature as specified in that draft at the time this
book went to press.

17.9 Reflective Metaprogramming
In the context of programming, reflection refers to the ability to
programmatically inspect features of the program (e.g., answering questions
such as Is a type an integer? or What nonstatic data members does a class type
contain?). Metaprogramming is the craft of “programming the program,” which
usually amounts to programmatically generating new code. Reflective
metaprogramming, then, is the craft of automatically synthesizing code that
adapts itself to existing properties (often, types) of a program.
In Part III of this book, we will explore how templates can achieve some
simple forms of reflection and metaprogramming (in some sense, template
instantiation is a form of metaprogramming, because it causes the synthesis of
new code). However, the capabilities of C++17 templates are rather limited
when it comes to reflection (e.g., it is not possible to answer the question What
nonstatic data members does a class type contain?) and the options for
metaprogramming are often inconvenient in various ways (in particular, the
syntax becomes unwieldy and the performance is disappointing).
Recognizing the potential of new facilities in this area, the C++
standardization committee created a study group (SG7) to explore options for

more powerful reflection. That group’s charter was later extended to cover
metaprogramming also. Here is an example of one of the options being
considered: Click here to view code image
template void report(T p) {
constexpr {
std::meta::info infoT = reflexpr(T);
for (std::meta::info : std::meta::data_members(infoT)) {
-> {
std::cout << (: std::meta::name(info) :)
<< ": " << p.(.info.) << ’\n’;
}
}
}
//code will be injected here
}

Quite a few new things are present in this code. First, the constexpr{… }
construct forces the statements in it to be evaluated at compile time, but if it
appears in a template, this evaluation is only done when the template is
instantiated. Second, the reflexpr() operator produces an expression of
opaque type std::meta::info that is a handle to reflected information
about its argument (the type substituted for T in this example). A library of
standard metafunctions permits querying this meta-information. One of those
standard metafunctions is std::meta::data_members, which produces a
sequence of std::meta::info objects describing the direct nonstatic data
members of its operand. So the for loop above is really a loop over the
nonstatic data members of p.
At the core of the metaprogramming capabilities of this system is the ability to
“inject” code in various scopes. The construct ->{… } injects statements and/or
declarations right after the statement or declaration that kicked off a
constexpr evaluation. In this example, that means after the constexpr{…
} construct. The code fragments being injected can contain certain patterns to be
replaced by computed values. In this example, (:… :) produces a string literal
value (the expression std::meta::name(info) produces a string-like
object representing the unqualified name of the entity—data member in this case
—represented by info). Similarly, the expression (.info.) produces an
identifier naming the entity represented by info. Other patterns to produce
types, template argument lists, etc. are also proposed.
With all that in place, instantiating the function template report() for a
type: Click here to view code image
struct X {

int x;
std::string s;
};

would produce an instantiation similar to Click here to view code image
template<> void report(X const& p) {
std::cout << "x" << ": " << "p.x" << ’\n’;
std::cout << "s" << ": " << "p.s" << ’\n’;
}

That is, this function automatically generates a function to output the nonstatic
data member values of a class type.
There are many applications for these types of capabilities. While it is likely
that something like this will eventually be adopted into the language, it is unclear
in what time frame it can be expected. That said, a few experimental
implementations of such systems have been demonstrated at the time of this
writing. (Just before going to press with this book, SG7 agreed on the general
direction of using constexpr evaluation and a value type somewhat like
std::meta::info to deal with reflective metaprogramming. The injection
mechanism presented here, however, was not agreed on, and most likely a
different system will be pursued.)

17.10 Pack Facilities
Parameter packs were introduced in C++11, but dealing with them often requires
recursive template instantiation techniques. Recall this outline of code discussed
in Section 14.6 on page 263: Click here to view code image
template
void f(Head&& h, Remainder&&… r) {
doSomething(h);
if constexpr (sizeof…(r) != 0) {
// handle the remainder recursively (perfectly forwarding the
arguments):
f(r…);
}
}

This example is made simpler by exploiting the features of the C++17 compiletime if statement (see Section 8.5 on page 134), but it remains a recursive
instantiation technique that may be somewhat expensive to compile.
Several committee proposals have tried to simplify this state of affairs
somewhat. One example is the introduction of a notation to pick a specific

element from a pack. In particular, for a pack P the notation P.[N] has been
suggested as a way to denote element N+1 of that pack. Similarly, there have
been proposals to denote “slices” of packs (e.g., using the notation P.[b, e]).
While examining such proposals, it has become clear that they interact
somewhat with the notion of reflective metaprogramming discussed above. It is
unclear at this time whether specific pack selection mechanisms will be added to
the language or whether metaprogramming facilities covering this need will be
provided instead.

17.11 Modules
Another upcoming major extension, modules, is only peripherally related to
templates, but it is still worth mentioning here because template libraries are
among the greatest beneficiaries of them.
Currently, library interfaces are specified in header files that are textually
#included into translation units. There are several downsides to this
approach, but the two most objectionable ones are that (a) the meaning of the
interface text may be accidentally modified by previously included code (e.g.,
through macros), and (b) reprocessing that text every time quickly dominates
build times.
Modules are a feature that allows library interfaces to be compiled into a
compiler-specific format, and then those interfaces can be “imported” into
translation units without being subject to macro expansion or modification of the
meaning of code by the accidental presence of addition declarations. What’s
more, a compiler can arrange to read only those parts of a compiled module file
that are relevant to the client code, thereby drastically accelerating the
compilation process.
Here is what a module definition may look like: Click here to view code
image
module MyLib;
void helper() {
…
}
export inline void libFunc() {
…
helper();
…
}

This module exports a function libFunc() that can be used in client code as
follows: Click here to view code image
import MyLib;
int main() {
libFunc();
}

Note that libFunc() is made visible to client code but the function
helper() is not, even though the compiled module file will likely contain
information about helper() to enable inlining.
The proposal to add modules to C++ is well on its way, and the
standardization committee is aiming at integrating it after C++17. One of the
concerns in developing such a proposal is how to transition from a world of
header files to a world of modules. There are already facilities to enable this to
some degree (e.g., the ability to include header files without making their
contents part of the module), and additional ones still under discussion (e.g., the
ability to export macros from modules).
Modules are particularly useful for template libraries because templates are
almost always fully defined in header files. Even including a basic standard
header like  amounts to processing tens of thousands of lines of C++
code (even when only a small number of the declarations in that header will be
referenced). Other popular libraries increase this by an order of magnitude.
Avoiding the costs of all this compilation will be of major interest to the C++
programmers dealing with large, complex code bases.
1 See, for example, document N4641 for the version of the Concepts TS in the
beginning of 2017.

Part III
Templates and Design
Programs are generally constructed using design patterns that map relatively
well on the mechanisms offered by a chosen programming language. Because
templates introduce a whole new language mechanism, it is not surprising to find
that they call for new design elements. We explore these elements in this part of
the book. Note that several of them are covered or used by the C++ standard
library.
Templates differ from more traditional language constructs in that they allow
us to parameterize the types and constants of our code. When combined with (1)
partial specialization and (2) recursive instantiation, this leads to a surprising
amount of expressive power.
Our presentation aims not only at listing various useful design elements but
also at conveying the principles that inspire such designs so that new techniques
may be created. Thus, the following chapters illustrate a large number of design
techniques, including: • Advanced polymorphic dispatching • Generic
programming with traits • Dealing with overloading and inheritance •
Metaprogramming • Heterogeneous structures and algorithms • Expression
templates We also present some notes to aid the debugging of templates.

Chapter 18
The Polymorphic Power of Templates
Polymorphism is the ability to associate different specific behaviors with a single
generic notation.1 Polymorphism is also a cornerstone of the object-oriented
programming paradigm, which in C++ is supported mainly through class
inheritance and virtual functions. Because these mechanisms are (at least in part)
handled at run time, we talk about dynamic polymorphism. This is usually what
is thought of when talking about plain polymorphism in C++. However,
templates also allow us to associate different specific behaviors with a single
generic notation, but this association is generally handled at compile time, which
we refer to as static polymorphism. In this chapter, we review the two forms of
polymorphism and discuss which form is appropriate in which situations.
Note that Chapter 22 will discuss some ways to deal with polymorphism after
introducing and discussing some design issues in between.

18.1 Dynamic Polymorphism
Historically, C++ started with supporting polymorphism only through the use of
inheritance combined with virtual functions.2 The art of polymorphic design in
this context consists of identifying a common set of capabilities among related
object types and declaring them as virtual function interfaces in a common base
class.
The poster child for this design approach is an application that manages
geometric shapes and allows them to be rendered in some way (e.g., on a
screen). In such an application, we might identify an abstract base class (ABC)
GeoObj, which declares the common operations and properties applicable to
geometric objects. Each concrete class for specific geometric objects then
derives from GeoObj (see Figure 18.1):

Figure 18.1. Polymorphism implemented via inheritance
Click here to view code image

poly/dynahier.hpp
#include "coord.hpp"
// common abstract base class GeoObj for geometric objects

class GeoObj {
public:
// draw geometric object:
virtual void draw() const = 0;
// return center of gravity of geometric object:
virtual Coord center_of_gravity() const = 0;
…
virtual ~GeoObj() = default;
};
// concrete geometric object class Circle
// - derived from GeoObj
class Circle : public GeoObj {
public:
virtual void draw() const override;
virtual Coord center_of_gravity() const override;
…
};
// concrete geometric object class Line
// - derived from GeoObj
class Line : public GeoObj {
public:
virtual void draw() const override;
virtual Coord center_of_gravity() const override;
…
};
…

After creating concrete objects, client code can manipulate these objects through
references or pointers to the common base class by using the virtual function
dispatch mechanism. Calling a virtual member function through a pointer or
reference to a base class subobject results in an invocation of the appropriate
member of the specific (“most-derived”) concrete object being referred to.
In our example, the concrete code can be sketched as follows: Click here to
view code image

poly/dynapoly.cpp
#include "dynahier.hpp"
#include 
// draw any GeoObj
void myDraw (GeoObj const& obj)
{
obj.draw(); // call draw() according to type of object
}
// compute distance of center of gravity between two GeoObjs
Coord distance (GeoObj const& x1, GeoObj const& x2)
{
Coord c = x1.center_of_gravity() - x2.center_of_gravity();
return c.abs(); // return coordinates as absolute values
}
// draw heterogeneous collection of GeoObjs
void drawElems (std::vector const& elems)
{
for (std::size_type i=0; idraw(); // call draw() according to type of element
}
}
int main()
{
Line l;
Circle c, c1, c2;
myDraw(l); // myDraw(GeoObj&) => Line::draw()
myDraw(c); // myDraw(GeoObj&) => Circle::draw()

distance(c1,c2); // distance(GeoObj&,GeoObj&)
distance(l,c); // distance(GeoObj&,GeoObj&)
std::vector coll; // heterogeneous collection
coll.push_back(&l); // insert line
coll.push_back(&c); // insert circle
drawElems(coll); // draw different kinds of GeoObjs
}

The key polymorphic interface elements are the functions draw() and
center_of_gravity(). Both are virtual member functions. Our example
demonstrates their use in the functions mydraw(), distance(), and
drawElems(). The latter functions are expressed using the common base type
GeoObj. A consequence of this approach is that it is generally unknown at
compile time which version of draw() or center_of_gravity() must be
called. However, at run time, the complete dynamic type of the objects for which
the virtual functions are invoked is accessed to dispatch the function calls.3
Hence, depending on the actual type of a geometric object, the appropriate
operation is performed: If mydraw() is called for a Line object, the
expression obj.draw() calls Line::draw(), whereas for a Circle
object, the function Circle::draw() is called. Similarly, with
distance(), the member functions center_of_gravity() appropriate
for the argument objects are called.
Perhaps the most compelling feature of this dynamic polymorphism is the
ability to handle heterogeneous collections of objects. drawElems() illustrates
this concept: The simple expression elems[i]->draw()
results in invocations of different member functions, depending on the dynamic
type of the element being iterated over.

18.2 Static Polymorphism
Templates can also be used to implement polymorphism. However, they don’t
rely on the factoring of common behavior in base classes. Instead, the
commonality is implicit in that the different “shapes” of an application must
support operations using common syntax (i.e., the relevant functions must have
the same names). Concrete classes are defined independently from each other
(see Figure 18.2). The polymorphic power is then enabled when templates are
instantiated with the concrete classes.

Figure 18.2. Polymorphism implemented via templates
For example, the function myDraw() in the previous section: Click here to
view code image
void myDraw (GeoObj const& obj) // GeoObj is abstract base class
{
obj.draw();
}

could conceivably be rewritten as
Click here to view code image
template
void myDraw (GeoObj const& obj) // GeoObj is template parameter
{
obj.draw();
}

Comparing the two implementations of myDraw(), we may conclude that the
main difference is the specification of GeoObj as a template parameter instead
of a common base class. There are, however, more fundamental differences
under the hood. For example, using dynamic polymorphism, we had only one
myDraw() function at run time, whereas with the template we have distinct
functions, such as myDraw() and myDraw().
We may attempt to recode the complete example of the previous section using
static polymorphism. First, instead of a hierarchy of geometric classes, we have
several individual geometric classes: Click here to view code image
poly/statichier.hpp
#include "coord.hpp"
// concrete geometric object class Circle
// - not derived from any class
class Circle {
public:

void draw() const;
Coord center_of_gravity() const;
…
};
// concrete geometric object class Line
// - not derived from any class
class Line {
public:
void draw() const;
Coord center_of_gravity() const;
…
};
…

Now, the application of these classes looks as follows: Click here to view code
image

poly/staticpoly.cpp
#include "statichier.hpp"
#include 
// draw any GeoObj
template
void myDraw (GeoObj const& obj)
{
obj.draw(); // call draw() according to type of object
}
// compute distance of center of gravity between two GeoObjs
template

Coord distance (GeoObj1 const& x1, GeoObj2 const& x2)
{
Coord c = x1.center_of_gravity() - x2.center_of_gravity();
return c.abs(); // return coordinates as absolute values
}
// draw homogeneous collection of GeoObjs
template
void drawElems (std::vector const& elems)
{
for (unsigned i=0; i(GeoObj&) => Line::draw()
myDraw(c); // myDraw(GeoObj&) => Circle::draw()
distance(c1,c2); //distance(GeoObj1&,GeoObj2&)
distance(l,c); // distance(GeoObj1&,GeoObj2&)
// std::vector coll; //ERROR: no heterogeneous collection
possible
std::vector coll; // OK: homogeneous collection possible
coll.push_back(l); // insert line
drawElems(coll); // draw all lines
}

As with myDraw(), GeoObj can no longer be used as a concrete parameter
type for distance(). Instead, we provide for two template parameters,
GeoObj1 and GeoObj2, which enables different combinations of geometric
object types to be accepted for the distance computation: Click here to view code
image
distance(l,c); // distance(GeoObj1&,GeoObj2&)

However, heterogeneous collections can no longer be handled transparently. This
is where the static part of static polymorphism imposes its constraint: All types
must be determined at compile time. Instead, we can easily introduce different
collections for different geometric object types. There is no longer a requirement
that the collection be limited to pointers, which can have significant advantages
in terms of performance and type safety.

18.3 Dynamic versus Static Polymorphism
Let’s categorize and compare both forms of polymorphism.
Terminology
Dynamic and static polymorphism provide support for different C++
programming idioms:4
• Polymorphism implemented via inheritance is bounded and dynamic: –
Bounded means that the interfaces of the types participating in the polymorphic
behavior are predetermined by the design of the common base class (other
terms for this concept are invasive and intrusive).
– Dynamic means that the binding of the interfaces is done at run time
(dynamically).
• Polymorphism implemented via templates is unbounded and static: –
Unbounded means that the interfaces of the types participating in the
polymorphic behavior are not predetermined (other terms for this concept are
noninvasive and nonintrusive).
– Static means that the binding of the interfaces is done at compile time
(statically).
So, strictly speaking, in C++ parlance, dynamic polymorphism and static
polymorphism are shortcuts for bounded dynamic polymorphism and unbounded
static polymorphism. In other languages, other combinations exist (e.g.,
Smalltalk provides unbounded dynamic polymorphism). However, in the context
of C++, the more concise terms dynamic polymorphism and static polymorphism
do not cause confusion.
Strengths and Weaknesses
Dynamic polymorphism in C++ exhibits the following strengths: •
Heterogeneous collections are handled elegantly.
• The executable code size is potentially smaller (because only one polymorphic
function is needed, whereas distinct template instances must be generated to
handle different types).
• Code can be entirely compiled; hence no implementation source must be
published (distributing template libraries usually requires distribution of the
source code of the template implementations).

In contrast, the following can be said about static polymorphism in C++: •
Collections of built-in types are easily implemented. More generally, the
interface commonality need not be expressed through a common base class.
• Generated code is potentially faster (because no indirection through pointers is
needed a priori and nonvirtual functions can be inlined much more often).
• Concrete types that provide only partial interfaces can still be used if only that
part ends up being exercised by the application.
Static polymorphism is often regarded as more type safe than dynamic
polymorphism because all the bindings are checked at compile time. For
example, there is little danger of inserting an object of the wrong type in a
container instantiated from a template. However, in a container expecting
pointers to a common base class, there is a possibility that these pointers
unintentionally end up pointing to complete objects of different types.
In practice, template instantiations can also cause some grief when different
semantic assumptions hide behind identical-looking interfaces. For example,
surprises can occur when a template that assumes an associative operator + is
instantiated for a type that is not associative with respect to that operator. In
practice, this kind of semantic mismatch occurs less often with inheritance-based
hierarchies, presumably because the interface specification is more explicitly
specified.
Combining Both Forms
Of course, you could combine both forms of polymorphism. For example, you
could derive different kinds of geometric objects from a common base class to
be able to handle heterogeneous collections of geometric objects. However, you
can still use templates to write code for a certain kind of geometric object.
The combination of inheritance and templates is further described in Chapter
21. We will see (among other things) how the virtuality of a member function
can be parameterized and how an additional amount of flexibility is afforded to
static polymorphism using the inheritance-based curiously recurring template
pattern (or CRTP).

18.4 Using Concepts
One argument against static polymorphism with templates is that the binding of
the interfaces is done by instantiating the corresponding templates. This means

that there is no common interface (class) to program against. Instead, any usage
of a template simply works if all instantiated code is valid. If it is not, this might
lead to hard-to-understand error messages or even cause valid but unintended
behavior.
For this reason, C++ language designers have been working on the ability to
explicitly provide (and check) interfaces for template parameters. Such an
interface is usually called a concept in C++. It denotes a set of constraints that
template arguments have to fulfill to successfully instantiate a template.
Despite many years of work in this area, concepts are still not part of standard
C++ as of C++17. Some compilers provide experimental support for such a
feature,5 however, and concepts will likely be part of the next standard after
C++17.
Concepts can be understood as a kind of “interface” for static polymorphism.
In our example, this might look as follows: Click here to view code image
poly/conceptsreq.hpp
#include "coord.hpp"
template
concept GeoObj = requires(T x) {
{ x.draw() } -> void;
{ x.center_of_gravity() } -> Coord;
…
};

Here, we use the keyword concept to define a concept GeoObj, which
constrains a type to have callable members draw() and
center_of_gravity() with appropriate result types.
Now, we can rewrite some of our example templates to include a requires
clause that constrains the template parameters with the GeoObj concept: Click
here to view code image

poly/conceptspoly.hpp
#include "conceptsreq.hpp"
#include 
// draw any GeoObj
template
requires GeoObj
void myDraw (T const& obj)
{
obj.draw(); // call draw() according to type of object
}
// compute distance of center of gravity between two GeoObjs
template
requires GeoObj && GeoObj
Coord distance (T1 const& x1, T2 const& x2)
{
Coord c = x1.center_of_gravity() - x2.center_of_gravity();
return c.abs(); // return coordinates as absolute values
}
// draw homogeneous collection of GeoObjs
template
requires GeoObj
void drawElems (std::vector const& elems)
{
for (std::size_type i=0; i
Iterator max_element (Iterator beg, //refers to start of collection
Iterator end) //refers to end of collection

{
// use only certain Iterator operations to traverse all elements
// of the collection to find the element with the maximum value
// and return its position as Iterator
…
}

Instead of providing all useful operations such as max_element() by every
linear container, the container has to provide only an iterator type to traverse the
sequence of values it contains and member functions to create such iterators:
Click here to view code image
namespace std {
template
class vector {
public:
using const_iterator = …; // implementation-specific iterator
… // type for constant vectors
const_iterator begin() const; // iterator for start of collection
const_iterator end() const; // iterator for end of collection
…
};
template
class list {
public:
using const_iterator = …; // implementation-specific iterator
… // type for constant lists
const_iterator begin() const; // iterator for start of collection
const_iterator end() const; // iterator for end of collection
…
};
}

Now, we can find the maximum of any collection by calling the generic
max_element() operation with the beginning and end of the collection as
arguments (special handling of empty collections is omitted): Click here to view
code image

poly/printmax.cpp

#include
#include
#include
#include
#include





"MyClass.hpp"

template
void printMax (T const& coll)
{
// compute position of maximum value
auto pos = std::max_element(coll.begin(),coll.end());
// print value of maximum element of coll (if any):
if (pos != coll.end()) {
std::cout << *pos << ’\n’;
}
else {
std::cout << "empty" << ’\n’;
}
}
int main()
{
std::vector c1;
std::list c2;
…
printMax(c1);
printMax(c2);
}

By parameterizing its operations in terms of these iterators, the STL avoids an
explosion in the number of operation definitions. Instead of implementing each
operation for every container, we implement the algorithm once so that it can be
used for every container. The generic glue is the iterators, which are provided by
the containers and used by the algorithms. This works because iterators have a
certain interface that is provided by the containers and used by the algorithms.
This interface is usually called a concept, which denotes a set of constraints that
a template has to fulfill to fit into this framework. In addition, this concept is
open for additional operations and data structures.
You’ll recall that we described a concepts language feature earlier in Section
18.4 on page 377(and in more detail in Appendix E), and indeed, the language
feature maps exactly onto the notion here. In fact, the term concept in this
context was first introduced by the designers of the STL to formalize their work.
Soon thereafter, work commenced to try to make these notions explicit in our
templates.
The forthcoming language feature will help us to specify and double check

requirements on iterators (since there are different iterator categories, such as
forward and bidirectional iterators, multiple corresponding concepts would be
involved; see Section E.3.1 on page 744). In today’s C++, however, the concepts
are mostly implicit in the specifications of our generic libraries (and the standard
C++ library in particular). Some features and techniques (e.g.,
static_assert and SFINAE) do permit some amount of automated
checking, fortunately.
In principle, functionality such as an STL-like approach could be
implemented with dynamic polymorphism. In practice, however, it would be of
limited use because the iterator concept is too lightweight compared with the
virtual function call mechanism. Adding an interface layer based on virtual
functions would most likely slow down our operations by an order of magnitude
(or more).
Generic programming is practical precisely because it relies on static
polymorphism, which resolves interfaces at compile time. On the other hand, the
requirement that the interfaces be resolved at compile time also calls for new
design principles that differ in many ways from object-oriented design
principles. Many of the most important of these generic design principles are
described in the remainder of this book. Additionally, Appendix E delves deeper
into generic programming as a development paradigm by describing direct
language support for the notion of concepts.

18.7 Afternotes
Container types were a primary motivation for the introduction of templates into
the C++ programming language. Prior to templates, polymorphic hierarchies
were a popular approach to containers. A popular example was the National
Institutes of Health Class Library (NIHCL), which to a large extent translated the
container class hierarchy of Smalltalk (see Figure 18.5).

Figure 18.5. Class hierarchy of the NIHCL
Much like the C++ standard library, the NIHCL supported a rich variety of
containers as well as iterators. However, the implementation followed the
Smalltalk style of dynamic polymorphism: Iterators used the abstract base
class Collection to operate on different types of collections: Bag c1;
Set c2;
…
Iterator i1(c1);
Iterator i2(c2);
…
Unfortunately, the price of this approach was high in terms of both running time
and memory usage. Running time was typically orders of magnitude worse than
equivalent code using the C++ standard library because most operations ended
up requiring a virtual call (whereas in the C++ standard library, many operations
are inlined, and no virtual functions are involved in iterator and container
interfaces). Furthermore, because (unlike Smalltalk) the interfaces were
bounded, built-in types had to be wrapped in larger polymorphic classes (such
wrappers were provided by the NIHCL), which in turn could lead to dramatic

increases in storage requirements.
Even in today’s age of templates, many projects still make suboptimal choices
in their approach to polymorphism. Clearly, there are many situations in which
dynamic polymorphism is the right choice. Heterogeneous iterations are an
example. However, in the same vein, many programming tasks are naturally and
efficiently solved using templates, and homogeneous containers are an example
of this.
Static polymorphism lends itself well to code fundamental computing
structures. In contrast, the need to choose a common base type implies that a
dynamic polymorphic library will normally have to make domain-specific
choices. It’s no surprise then that the STL part of the C++ standard library never
included polymorphic containers, but it contains a rich set of containers and
iterators that use static polymorphism (as demonstrated in Section 18.6 on page
380).
Medium and large C++ programs typically need to handle both kinds of
polymorphism discussed in this chapter. In some situations, it may even be
necessary to combine them very intimately. In many cases, the optimal design
choices are clear in light of our discussion, but spending some time thinking
about long-term, potential evolutions almost always pays off.
1 Polymorphism literally refers to the condition of having many forms or shapes
(from the Greek polymorphos).
2 Strictly speaking, macros can also be thought of as an early form of static
polymorphism. However, they are left out of consideration because they are
mostly orthogonal to the other language mechanisms.
3 That is, the encoding of polymorphic base class subobjects includes some
(mostly hidden) data that enables this run-time dispatch.
4 For a detailed discussion of polymorphism terminology, see also Sections 6.5
to 6.7 of [CzarneckiEiseneckerGenProg].
5 GCC 7, for example, provides the option -fconcepts.

Chapter 19
Implementing Traits
Templates enable us to parameterize classes and functions for various types. It
could be tempting to introduce as many template parameters as possible to
enable the customization of every aspect of a type or algorithm. In this way, our
“templatized” components could be instantiated to meet the exact needs of client
code. However, from a practical point of view, it is rarely desirable to introduce
dozens of template parameters for maximal parameterization. Having to specify
all the corresponding arguments in the client code is overly tedious, and each
additional template parameter complicates the contract between the component
and its client.
Fortunately, it turns out that most of the extra parameters we would introduce
have reasonable default values. In some cases, the extra parameters are entirely
determined by a few main parameters, and we’ll see that such extra parameters
can be omitted altogether. Other parameters can be given default values that
depend on the main parameters and will meet the needs of most situations, but
the default values must occasionally be overridden (for special applications). Yet
other parameters are unrelated to the main parameters: In a sense, they are
themselves main parameters except that there exist default values that almost
always fit the bill.
Traits (or traits templates) are C++ programming devices that greatly facilitate
the management of the sort of extra parameters that come up in the design of
industrial-strength templates. In this chapter, we show a number of situations in
which they prove useful and demonstrate various techniques that will enable you
to write robust and powerful devices of your own.
Most of the traits presented here are available in the C++ standard library in
some form. However, for clarity’s sake, we often present simplified
implementations that omit some details present in industrial-strength
implementations (like those of the standard library). For this reason, we also use
our own naming scheme, which, however, maps easily to the standard traits.

19.1 An Example: Accumulating a Sequence

Computing the sum of a sequence of values is a fairly common computational
task. However, this seemingly simple problem provides us with an excellent
example to introduce various levels at which policy classes and traits can help.

19.1.1 Fixed Traits
Let’s first assume that the values of the sum we want to compute are stored in an
array, and we are given a pointer to the first element to be accumulated and a
pointer one past the last element to be accumulated. Because this book is about
templates, we wish to write a template that will work for many types. The
following may seem straightforward by now:1
Click here to view code image

traits/accum1.hpp
#ifndef ACCUM_HPP
#define ACCUM_HPP
template
T accum (T const* beg, T const* end)
{
T total{}; // assume this actually creates a zero value
while (beg != end) {
total += *beg;
++beg;
}
return total;
}
#endif //ACCUM_HPP

The only slightly subtle decision here is how to create a zero value of the correct
type to start our summation. We use value initialization (with the {…} notation)
here as introduced in Section 5.2 on page 68. It means that the local object
total is initialized either by its default constructor or by zero (which means
nullptr for pointers and false for Boolean values).
To motivate our first traits template, consider the following code that makes
use of our accum(): Click here to view code image
traits/accum1.cpp
#include "accum1.hpp"
#include 

int main()
{
// create array of 5 integer values
int num[] = { 1, 2, 3, 4, 5 };
// print average value
std::cout << "the average value of the integer values is "
<< accum(num, num+5) / 5
<< ’\n’;
// create array of character values
char name[] = "templates";
int length = sizeof(name)-1;
// (try to) print average character value
std::cout << "the average value of the characters in \""
<< name << "\" is "
<< accum(name, name+length) / length
<< ’\n’;
}

In the first half of the program, we use accum() to sum five integer values:
Click here to view code image
int num[] = { 1, 2, 3, 4, 5 };
…
accum(num0, num+5)

The average integer value is then obtained by simply dividing the resulting sum
by the number of values in the array.
The second half of the program attempts to do the same for all letters in the
word templates (provided the characters from a to z form a contiguous
sequence in the actual character set, which is true for ASCII but not for
EBCDIC).2 The result should presumably lie between the value of a and the
value of z. On most platforms today, these values are determined by the ASCII
codes: a is encoded as 97 and z is encoded as 122. Hence, we may expect a
result between 97 and 122. However, on our platform, the output of the program
is as follows: Click here to view code image
the average value of the integer values is 3
the average value of the characters in "templates" is -5

The problem here is that our template was instantiated for the type char, which
turns out to be too small a range for the accumulation of even relatively small
values. Clearly, we could resolve this by introducing an additional template
parameter AccT that describes the type used for the variable total (and hence

the return type). However, this would put an extra burden on all users of our
template: They would have to specify an extra type in every invocation of our
template. In our example, we may therefore need to write the following:
accum(name,name+5) This is not an excessive constraint, but it can be
avoided.
An alternative approach to the extra parameter is to create an association
between each type T for which accum() is called and the corresponding type
that should be used to hold the accumulated value. This association could be
considered characteristic of the type T, and therefore the type in which the sum
is computed is sometimes called a trait of T. As is turns out, our association can
be encoded as specializations of a template: Click here to view code image
traits/accumtraits2.hpp
template
struct AccumulationTraits;
template<>
struct AccumulationTraits {
using AccT = int;
};
template<>
struct AccumulationTraits {
using AccT = int;
};
template<>
struct AccumulationTraits {
using AccT = long;
};
template<>
struct AccumulationTraits {
using AccT = unsigned long;
};
template<>
struct AccumulationTraits {
using AccT = double;
};

The template AccumulationTraits is called a traits template because it
holds a trait of its parameter type. (In general, there could be more than one trait
and more than one parameter.) We chose not to provide a generic definition of
this template because there isn’t a great way to select a good accumulation type

when we don’t know what the type is. However, an argument could be made that
T itself is often a good candidate for such a type (although clearly not in our
earlier example).
With this in mind, we can rewrite our accum() template as follows:3
Click here to view code image

traits/accum2.hpp
#ifndef ACCUM_HPP
#define ACCUM_HPP
#include "accumtraits2.hpp"
template
auto accum (T const* beg, T const* end)
{
// return type is traits of the element type
using AccT = typename AccumulationTraits::AccT;
AccT total{}; // assume this actually creates a zero value
while (beg != end) {
total += *beg;
++beg;
}
return total;
}
#endif //ACCUM_HPP

The output of our sample program then becomes what we expect: Click here to
view code image
the average value of the integer values is 3
the average value of the characters in "templates" is 108

Overall, the changes aren’t very dramatic considering that we have added a very
useful mechanism to customize our algorithm. Furthermore, if new types arise
for use with accum(), an appropriate AccT can be associated with it simply by
declaring an additional explicit specialization of the AccumulationTraits
template. Note that this can be done for any type: fundamental types, types that
are declared in other libraries, and so forth.

19.1.2 Value Traits

So far, we have seen that traits represent additional type information related to a
given “main” type. In this section, we show that this extra information need not
be limited to types. Constants and other classes of values can be associated with
a type as well.
Our original accum() template uses the default constructor of the return
value to initialize the result variable with what is hoped to be a zero-like value:
Click here to view code image
AccT total{}; // assume this actually creates a zero value
…
return total; Clearly, there is no guarantee that this produces a
good value to start the accumulation loop. Type AccT may not even
have a default constructor.

Again, traits can come to the rescue. For our example, we can add a new value
trait to our AccumulationTraits: traits/accumtraits3.hpp
template
struct AccumulationTraits;
template<>
struct AccumulationTraits {
using AccT = int;
static AccT const zero = 0;
};
template<>
struct AccumulationTraits {
using AccT = int;
static AccT const zero = 0;
};
template<>
struct AccumulationTraits {
using AccT = long;
static AccT const zero = 0;
};
…

In this case, our new trait provides an zero element as a constant that can be
evaluated at compile time. Thus, accum() becomes the following: Click here
to view code image
traits/accum3.hpp
#ifndef ACCUM_HPP
#define ACCUM_HPP

#include "accumtraits3.hpp"
template
auto accum (T const* beg, T const* end)
{
// return type is traits of the element type
using AccT = typename AccumulationTraits::AccT;
AccT total = AccumulationTraits::zero; // init total by trait value
while (beg != end) {
total += *beg;
++beg;
}
return total;
}
#endif // ACCUM_HPP

In this code, the initialization of the accumulation variable remains
straightforward: Click here to view code image
AccT total = AccumulationTraits::zero;

A drawback of this formulation is that C++ allows us to initialize a static
constant data member inside its class only if it has an integral or enumeration
type.
constexpr static data members are slightly more general, allowing floatingpoint types as well as other literal types: Click here to view code image
template<>
struct AccumulationTraits {
using Acct = float;
static constexpr float zero = 0.0f;
};

However, neither const nor constexpr permit nonliteral types to be
initialized this way. For example, a user-defined arbitrary-precision BigInt
type might not be a literal type, because typically it has to allocate components
on the heap, which usually precludes it from being a literal type, or just because
the required constructor is not constexpr. The following specialization is then
an error: Click here to view code image
class BigInt {
BigInt(long long);
…
};
…
template<>
struct AccumulationTraits {

using AccT = BigInt;
static constexpr BigInt zero = BigInt{0}; // ERROR: not a literal
type
};

The straightforward alternative is not to define the value trait in its class: Click
here to view code image
template<>
struct AccumulationTraits {
using AccT = BigInt;
static BigInt const zero; // declaration only
};

The initializer then goes in a source file and looks something like the following:
Click here to view code image
BigInt const AccumulationTraits::zero = BigInt{0}; Although
this works, it has the disadvantage of being more verbose (code must
be added in two places), and it is potentially less efficient because
compilers are typically unaware of definitions in other files.

In C++17, this can be addressed using inline variables: Click here to view
code image
template<>
struct AccumulationTraits {
using AccT = BigInt;
inline static BigInt const zero = BigInt{0}; // OK since C++17
};

An alternative that works prior to C++17 is to use inline member functions for
value traits that won’t always yield integral values. Again, such a function can be
declared constexpr if it returns a literal type.4
For example, we could rewrite AccumulationTraits as follows: Click
here to view code image
traits/accumtraits4.hpp
template
struct AccumulationTraits;
template<>
struct AccumulationTraits {
using AccT = int;
static constexpr AccT zero() {
return 0;
}
};
template<>

struct AccumulationTraits {
using AccT = int;
static constexpr AccT zero() {
return 0;
}
};
template<>
struct AccumulationTraits {
using AccT = long;
static constexpr AccT zero() {
return 0;
}
};
template<>
struct AccumulationTraits {
using AccT = unsigned long;
static constexpr AccT zero() {
return 0;
}
};
template<>
struct AccumulationTraits {
using AccT = double;
static constexpr AccT zero() {
return 0;
}
};
…

and then extend these traits for our own types: Click here to view code image
traits/accumtraits4bigint.hpp
template<>
struct AccumulationTraits {
using AccT = BigInt;
static BigInt zero() {
return BigInt{0};
}
};

For the application code, the only difference is the use of function call syntax
(instead of the slightly more concise access to a static data member): Click here
to view code image
AccT total = AccumulationTraits::zero(); // init total by trait

function

Clearly, traits can be more than just extra types. In our example, they can be a
mechanism to provide all the necessary information that accum() needs about
the element type for which it is called. This is the key to the notion of traits:
Traits provide an avenue to configure concrete elements (mostly types) for
generic computations.

19.1.3 Parameterized Traits
The use of traits in accum() in the previous sections is called fixed, because
once the decoupled trait is defined, it cannot be replaced in the algorithm. There
may be cases when such overriding is desirable. For example, we may happen to
know that a set of float values can safely be summed into a variable of the
same type, and doing so may buy us some efficiency.
We can address this problem by adding a template parameter AT for the trait
itself having a default value determined by our traits template: Click here to
view code image
traits/accum5.hpp
#ifndef ACCUM_HPP
#define ACCUM_HPP
#include "accumtraits4.hpp"
template>
auto accum (T const* beg, T const* end)
{
typename AT::AccT total = AT::zero();
while (beg != end) {
total += *beg;
++beg;
}
return total;
}
#endif //ACCUM_HPP

In this way, many users can omit the extra template argument, but those with
more exceptional needs can specify an alternative to the preset accumulation
type. Presumably, most users of this template would never have to provide the
second template argument explicitly because it can be configured to an

appropriate default for every type deduced for the first argument.

19.2 Traits versus Policies and Policy Classes
So far we have equated accumulation with summation. However, we can
imagine other kinds of accumulations. For example, we could multiply the
sequence of given values. Or, if the values were strings, we could concatenate
them. Even finding the maximum value in a sequence could be formulated as an
accumulation problem. In all these alternatives, the only accum() operation
that needs to change is total += *beg. This operation can be called a policy
of our accumulation process.
Here is an example of how we could introduce such a policy in our accum()
function template: Click here to view code image
traits/accum6.hpp
#ifndef ACCUM_HPP
#define ACCUM_HPP
#include "accumtraits4.hpp"
#include "sumpolicy1.hpp"
template>
auto accum (T const* beg, T const* end)
{
using AccT = typename Traits::AccT;
AccT total = Traits::zero();
while (beg != end) {
Policy::accumulate(total, *beg);
++beg;
}
return total;
}
#endif //ACCUM_HPP

In this version of accum() SumPolicy is a policy class, that is, a class that
implements one or more policies for an algorithm through an agreed-upon
interface.5 SumPolicy could be written as follows: Click here to view code
image

traits/sumpolicy1.hpp
#ifndef SUMPOLICY_HPP
#define SUMPOLICY_HPP
class SumPolicy {
public:
template
static void accumulate (T1& total, T2 const& value) {
total += value;
}
};
#endif //SUMPOLICY_HPP

By specifying a different policy to accumulate values, we can compute different
things. Consider, for example, the following program, which intends to
determine the product of some values: Click here to view code image
traits/accum6.cpp
#include "accum6.hpp"
#include 
class MultPolicy {
public:
template
static void accumulate (T1& total, T2 const& value) {
total *= value;
}
};
int main()
{
// create array of 5 integer values
int num[] = { 1, 2, 3, 4, 5 };
// print product of all values
std::cout << "the product of the integer values is "
<< accum(num, num+5)
<< ’\n’;
}

However, the output of this program isn’t what we would like: Click here to
view code image
the product of the integer values is 0

The problem here is caused by our choice of initial value: Although 0 works
well for summation, it does not work for multiplication (a zero initial value

forces a zero result for accumulated multiplications). This illustrates that
different traits and policies may interact, underscoring the importance of careful
template design.
In this case, we may recognize that the initialization of an accumulation loop
is a part of the accumulation policy. This policy may or may not make use of the
trait zero(). Other alternatives are not to be forgotten: Not everything must be
solved with traits and policies. For example, the std::accumulate()
function of the C++ standard library takes the initial value as a third (function
call) argument.

19.2.1 Traits and Policies: What’s the Difference?
A reasonable case can be made in support of the fact that policies are just a
special case of traits. Conversely, it could be claimed that traits just encode a
policy.
The New Shorter Oxford English Dictionary (see [NewShorterOED]) has this
to say: • trait n… . a distinctive feature characterizing a thing
• policy n… . any course of action adopted as advantageous or expedient
Based on this, we tend to limit the use of the term policy classes to classes that
encode an action of some sort that is largely orthogonal with respect to any other
template argument with which it is combined. This is in agreement with Andrei
Alexandrescu’s statement in his book Modern C++ Design (see page 8 of
[AlexandrescuDesign]):6
Policies have much in common with traits but differ in that they put less
emphasis on type and more on behavior.
Nathan Myers, who introduced the traits technique, proposed the following more
open-ended definition (see [MyersTraits]): Traits class: A class used in place of
template parameters. As a class, it aggregates useful types and constants; as a
template, it provides an avenue for that “extra level of indirection” that solves
all software problems.
In general, we therefore tend to use the following (slightly fuzzy) definitions: •
Traits represent natural additional properties of a template parameter.
• Policies represent configurable behavior for generic functions and types (often
with some commonly used defaults).

To elaborate further on the possible distinctions between the two concepts, we
list the following observations about traits: • Traits can be useful as fixed traits
(i.e., without being passed through template parameters).
• Traits parameters usually have very natural default values (which are rarely
overridden, or simply cannot be overridden).
• Traits parameters tend to depend tightly on one or more main parameters.
• Traits mostly combine types and constants rather than member functions.
• Traits tend to be collected in traits templates.
For policy classes, we make the following observations:
• Policy classes don’t contribute much if they aren’t passed as template
parameters.
• Policy parameters need not have default values and are often specified
explicitly (although many generic components are configured with commonly
used default policies).
• Policy parameters are mostly orthogonal to other parameters of a template.
• Policy classes mostly combine member functions.
• Policies can be collected in plain classes or in class templates.
However, there is certainly an indistinct line between both terms. For example,
the character traits of the C++ standard library also define functional behavior
such as comparing, moving, and finding characters. And by replacing these
traits, we can define string classes that behave in a case-insensitive manner (see
Section 13.2.15 in [JosuttisStdLib]) while keeping the same character type. Thus,
although they are called traits, they have some properties associated with
policies.

19.2.2 Member Templates versus Template Template
Parameters
To implement an accumulation policy, we chose to express SumPolicy and
MultPolicy as ordinary classes with a member template. An alternative
consists of designing the policy class interface using class templates, which are
then used as template template arguments (see Section 5.7 on page 83 and
Section 12.2.3 on page 187). For example, we could rewrite SumPolicy as a
template: Click here to view code image
traits/sumpolicy2.hpp

#ifndef SUMPOLICY_HPP
#define SUMPOLICY_HPP
template
class SumPolicy {
public:
static void accumulate (T1& total, T2 const& value) {
total += value;
}
};
#endif //SUMPOLICY_HPP

The interface of Accum can then be adapted to use a template template
parameter: Click here to view code image
traits/accum7.hpp
#ifndef ACCUM_HPP
#define ACCUM_HPP
#include "accumtraits4.hpp"
#include "sumpolicy2.hpp"
template class Policy = SumPolicy,
typename Traits = AccumulationTraits>
auto accum (T const* beg, T const* end)
{
using AccT = typename Traits::AccT;
AccT total = Traits::zero();
while (beg != end) {
Policy::accumulate(total, *beg);
++beg;
}
return total;
}
#endif//ACCUM_HPP

The same transformation can be applied to the traits parameter. (Other variations
on this theme are possible: For example, instead of explicitly passing the AccT
type to the policy type, it may be advantageous to pass the accumulation trait
and have the policy determine the type of its result from a traits parameter.) The
major advantage of accessing policy classes through template template
parameters is that it makes it easier to have a policy class carry with it some state
information (i.e., static data members) with a type that depends on the template

parameters. (In our first approach, the static data members would have to be
embedded in a member class template.) However, a downside of the template
template parameter approach is that policy classes must now be written as
templates, with the exact set of template parameters defined by our interface.
This can make the expression of the traits themselves more verbose and less
natural than a simple nontemplate class.

19.2.3 Combining Multiple Policies and/or Traits
As our development has shown, traits and policies don’t entirely do away with
having multiple template parameters. However, they do reduce their number to
something manageable. An interesting question, then, is how to order such
multiple parameters.
A simple strategy is to order the parameters according to the increasing
likelihood of their default value to be selected. Typically, this would mean that
the traits parameters follow the policy parameters because the latter are more
often overridden in client code. (The observant reader may have noticed this
strategy in our development.) If we are willing to add a significant amount of
complexity to our code, an alternative exists that essentially allows us to specify
the nondefault arguments in any order. Refer to Section 21.4 on page 512 for
details.

19.2.4 Accumulation with General Iterators
Before we end this introduction to traits and policies, it is instructive to look at
one version of accum() that adds the capability to handle generalized iterators
(rather than just pointers), as expected from an industrial-strength generic
component. Interestingly, this still allows us to call accum() with pointers
because the C++ standard library provides iterator traits. (Traits are
everywhere!) Thus, we could have defined our initial version of accum() as
follows (ignoring our later refinements):7
Click here to view code image

traits/accum0.hpp
#ifndef ACCUM_HPP
#define ACCUM_HPP

#include 
template
auto accum (Iter start, Iter end)
{
using VT = typename std::iterator_traits::value_type;
VT total{}; // assume this actually creates a zero value
while (start != end) {
total += *start;
++start;
}
return total;
}
#endif //ACCUM_HPP

The std::iterator_traits structure encapsulates all the relevant
properties of iterators. Because a partial specialization for pointers exists, these
traits are conveniently used with any ordinary pointer types. Here is how a
standard library implementation may implement this support: Click here to view
code image
namespace std {
template
struct iterator_traits {
using difference_type = ptrdiff_t;
using value_type = T;
using pointer = T*;
using reference = T&;
using iterator_category = random_access_iterator_tag ;
};
}

However, there is no type for the accumulation of values to which an iterator
refers; hence we still need to design our own AccumulationTraits.

19.3 Type Functions
The initial traits example demonstrates that we can define behavior that depends
on types. Traditionally, in C and C++, we define functions that could more
specifically be called value functions: They take some values as arguments and
return another value as a result. With templates, we can additionally define type
functions: functions that takes some type as arguments and produce a type or a

constant as a result.
A very useful built-in type function is sizeof, which returns a constant
describing the size (in bytes) of the given type argument. Class templates can
also serve as type functions. The parameters of the type function are the template
parameters, and the result is extracted as a member type or member constant. For
example, the sizeof operator could be given the following interface: Click
here to view code image
traits/sizeof.cpp
#include 
#include 
template
struct TypeSize {
static std::size_t const value = sizeof(T);
};
int main()
{
std::cout << "TypeSize::value = "
<< TypeSize::value << ’\n’;
}

This may not seem very useful, since we have the built-in sizeof operator
available, but note that TypeSize is a type, and it can therefore be passed
as a class template argument itself. Alternatively, TypeSize is a template and
can be passed as a template template argument.
In what follows, we develop a few more general-purpose type functions that
can be used as traits classes in this way.

19.3.1 Element Types
Assume that we have a number of container templates, such as
std::vector<> and std::list<>, as well as built-in arrays. We want a
type function that, given such a container type, produces the element type. This
can be achieved using partial specialization: Click here to view code image
traits/elementtype.hpp
#include 
#include 

template
struct ElementT; // primary template
template
struct ElementT> { //partial specialization for
std::vector
using Type = T;
};
template
struct ElementT> { //partial specialization for std::list
using Type = T;
};
…
template
struct ElementT { //partial specialization for arrays of known
bounds
using Type = T;
};
template
struct ElementT { //partial specialization for arrays of unknown
bounds
using Type = T;
};
…

Note that we should provide partial specializations for all possible array types
(see Section 5.4 on page 71 for details).
We can use the type function as follows:
Click here to view code image

traits/elementtype.cpp
#include
#include
#include
#include

"elementtype.hpp"




template
void printElementType (T const& c)
{
std::cout << "Container of "
<< typeid(typename ElementT::Type).name()
<< " elements.\n";
}
int main()

{
std::vector s;
printElementType(s);
int arr[42];
printElementType(arr);
}

The use of partial specialization allows us to implement the type function
without requiring the container types to know about it. In many cases, however,
the type function is designed along with the applicable types, and the
implementation can be simplified. For example, if the container types define a
member type value_type (as the standard containers do), we can write the
following: Click here to view code image
template
struct ElementT {
using Type = typename C::value_type;
};

This can be the default implementation, and it does not exclude specializations
for container types that do not have an appropriate member type value_type
defined.
Nonetheless, it is usually advisable to provide member type definitions for
class template type parameters so that they can be accessed more easily in
generic code (like the standard container templates do). The following sketches
the idea: Click here to view code image
template
class X {
public:
using … = T1;
using … = T2;
…
};

How is a type function useful? It allows us to parameterize a template in terms
of a container type without also requiring parameters for the element type and
other characteristics. For example, instead of Click here to view code image
template
T sumOfElements (C const& c); which requires syntax like
sumOfElements(list) to specify the element type explicitly, we
can declare Click here to view code image
template
typename ElementT::Type sumOfElements (C const& c); where the
element type is determined from the type function.

Observe how the traits are implemented as an extension to existing types; that

is, we can define these type functions even for fundamental types and types of
closed libraries.
In this case, the type ElementT is called a traits class because it is used to
access a trait of the given container type C (in general, more than one trait can be
collected in such a class). Thus, traits classes are not limited to describing
characteristics of container parameters but of any kind of “main parameters.”
As a convenience, we can create an alias template for type functions. For
example, we could introduce Click here to view code image
template
using ElementType = typename ElementT::Type; which allows us to
further simplify the declaration of sumOfElements above to Click here
to view code image
template
ElementType sumOfElements (C const& c);

19.3.2 Transformation Traits
In addition to providing access to particular aspects of a main parameter type,
traits can also perform transformations on types, such as adding or removing
references or const and volatile qualifiers.
Removing References
For example, we can implement a RemoveReferenceT trait that turns
reference types into their underlying object or function types, and leaves
nonreference types alone: Click here to view code image
traits/removereference.hpp
template
struct RemoveReferenceT {
using Type = T;
};
template
struct RemoveReferenceT {
using Type = T;
};
template
struct RemoveReferenceT {
using Type = T;

};

Again, a convenience alias template makes the usage simpler: Click here to view
code image
template
using RemoveReference = typename RemoveReference::Type; Removing
the reference from a type is typically useful when the type was
derived using a construct that sometimes produces reference types,
such as the special deduction rule for function parameters of type
T&& discussed in Section 15.6 on page 277.

The C++ standard library provides a corresponding type trait
std::remove_reference<>, which is described in Section D.4 on page
729.
Adding References
Similarly, we can take an existing type and create an lvalue or rvalue reference
from it (along with the usual convenience alias templates): Click here to view
code image
traits/addreference.hpp
template
struct AddLValueReferenceT {
using Type = T&;
};
template
using AddLValueReference = typename AddLValueReferenceT::Type;
template
struct AddRValueReferenceT {
using Type = T&&;
};
template
using AddRValueReference = typename AddRValueReferenceT::Type; The
rules of reference collapsing (Section 15.6 on page 277) apply here.
For example, calling AddLValueReference produces type int&
(there is therefore no need to implement them manually via partial
specialization).

If we leave AddLValueReferenceT and AddRValueReferenceT as
they are and do not introduce specializations of them, then the convenience
aliases can actually be simplified to Click here to view code image

template
using AddLValueReferenceT = T&;
template
using AddRValueReferenceT = T&&; which can be instantiated without
instantiating a class template (and is therefore a lighter-weight
process). However, this is risky, as we may well want to specialize
these template for special cases. For example, as written above, we
cannot use void as a template argument for these templates. A few
explicit specializations can take care of that: Click here to view
code image
template<>
struct AddLValueReferenceT {
using Type = void;
};
template<>
struct AddLValueReferenceT {
using Type = void const;
};
template<>
struct AddLValueReferenceT {
using Type = void volatile;
};
template<>
struct AddLValueReferenceT {
using Type = void const volatile;
};

and similarly for AddRValueReferenceT.
With that in place, the convenience alias template must be formulated in terms
of the class templates to ensure that the specializations are picked up also (since
alias templates cannot be specialized).
The C++ standard library provides corresponding type traits
std::add_lvalue_reference<> and
std::add_rvalue_reference<>, which are described in Section D.4 on
page 729. The standard templates include the specializations for void types.
Removing Qualifiers
Transformation traits can break down or introduce any kind of compound type,
not just references. For example, we can remove a const qualifier if present:
Click here to view code image

traits/removeconst.hpp
template
struct RemoveConstT {
using Type = T;
};
template
struct RemoveConstT {
using Type = T;
};
template
using RemoveConst = typename RemoveConstT::Type; Moreover,
transformation traits can be composed, such as creating a RemoveCVT
trait that removes both const and volatile: Click here to view code
image

traits/removecv.hpp
#include "removeconst.hpp"
#include "removevolatile.hpp"
template
struct RemoveCVT : RemoveConstT::Type> {
};
template
using RemoveCV = typename RemoveCVT::Type; There are two things to
note with the definition of RemoveCVT. First, it is making use of both
RemoveConstT and the related RemoveVolatileT, first removing the
volatile (if present) and then passing the resulting type to
RemoveConstT.8 Second, it is using metafunction forwarding to inherit
the Type member from RemoveConstT rather than declaring its own Type
member that is identical to the one in the RemoveConstT
specialization. Here, metafunction forwarding is used simply to reduce
the amount of typing in the definition of RemoveCVT. However,
metafunction forwarding is also useful when the metafunction is not
defined for all inputs, a technique that will be discussed further in
Section 19.4 on page 416.

The convenience alias template RemoveCV could be simplified to Click here
to view code image
template
using RemoveCV = RemoveConst>; Again, this works
only if RemoveCVT is not specialized. Unlike in the case of
AddLValueReference and AddRValueReference, we cannot think of any
reasons for such specializations.

The C++ standard library also provides corresponding type traits

std::remove_volatile<>, std::remove_const<>, and
std::remove_cv<>, which are described in Section D.4 on page 728.
Decay
To round out our discussion of transformation traits, we develop a trait that
mimics type conversions when passing arguments to parameters by value.
Derived from C, this means that the arguments decay (turning array types into
pointers and function types into pointer-to-function types; see Section 7.4 on
page 115 and Section 11.1.1 on page 159) and delete any top-level const,
volatile, or reference qualifiers (because top-level type qualifiers on
parameter types are ignored when resolving a function call).
The effect of this pass-by-value can be seen in the following program, which
prints the actual parameter type produced after the compiler decays the specified
type: Click here to view code image
traits/passbyvalue.cpp
#include 
#include 
#include 
template
void f(T)
{
}
template
void printParameterType(void (*)(A))
{
std::cout
std::cout
std::cout
std::cout
}

<<
<<
<<
<<

"Parameter type: " << typeid(A).name() << ’\n’;
"- is int: " <::value << ’\n’;
"- is const: " <::value << ’\n’;
"- is pointer: " <::value << ’\n’;

int main()
{
printParameterType(&f);
printParameterType(&f);
printParameterType(&f);
printParameterType(&f);
}

In the output of the program, the int parameter has been left unchanged, but the

int const, int[7], and int(int) parameters have decayed to int,
int*, and int(*)(int), respectively.
We can implement a trait that produces the same type conversion of passing
by value. To match to the C++ standard library trait std::decay, we name it
DecayT.9 Its implementation combines several of the techniques described
above First, we define the nonarray, nonfunction case, which simply deletes any
const and volatile qualifiers: Click here to view code image
template
struct DecayT : RemoveCVT {
};

Next, we handle the array-to-pointer decay, which requires us to recognize any
array types (with or without a bound) using partial specialization: Click here to
view code image
template
struct DecayT {
using Type = T*;
};
template
struct DecayT {
using Type = T*;
};

Finally, we handle the function-to-pointer decay, which has to match any
function type, regardless of the return type or the number of parameter types. For
this, we employ variadic templates: Click here to view code image
template
struct DecayT {
using Type = R (*)(Args…);
};
template
struct DecayT {
using Type = R (*)(Args…, …);
};

Note that the second partial specialization matches any function type that uses Cstyle varargs.10 Together, the primary DecayT template and its four partial
specialization implement parameter type decay, as illustrated by this example
program: Click here to view code image
traits/decay.cpp
#include 

#include 
#include 
#include "decay.hpp"
template
void printDecayedType()
{
using A = typename DecayT::Type;
std::cout << "Parameter type: " << typeid(A).name() << ’\n’;
std::cout << "- is int: " << std::is_same::value << ’\n’;
std::cout << "- is const: " << std::is_const::value << ’\n’;
std::cout << "- is pointer: " << std::is_pointer::value << ’\n’;
}
int main()
{
printDecayedType();
printDecayedType();
printDecayedType();
printDecayedType();
}

As usual, we provide a convenience alias template: Click here to view code
image
template typename T>
using Decay = typename DecayT::Type; As written, the C++ standard
library also provides a corresponding type traits std::decay<>, which
is described in Section D.4 on page 731.

19.3.3 Predicate Traits
So far we have studied and developed type functions of a single type: Given one
type, provide other related types or constants. In general, however, we can
develop type functions that depend on multiple arguments. This also leads to a
special form of type traits, type predicates (type functions yielding a Boolean
value).
IsSameT
The IsSameT trait yields whether two types are equal: Click here to view code
image
traits/issame0.hpp

template
struct IsSameT {
static constexpr bool value = false;
};
template
struct IsSameT {
static constexpr bool value = true;
};

Here the primary template defines that, in general, two different types passed as
template arguments differ. so that the value member is false. However,
using partial specialization, when we have the special case that the two passed
types are the same, value is true.
For example, the following expression checks whether a passed template
parameters is an integer: Click here to view code image
if (IsSameT::value) …

For traits that produce a constant value, we cannot provide an alias template, but
we can provide a constexpr variable template that fulfills the same role:
Click here to view code image
template
constexpr bool isSame = IsSameT::value; The C++ standard
library provides a corresponding type trait std::is_same<>, which is
described in Section D.3.3 on page 726

true_type and false_type
We can significantly improve the definition of IsSameT by providing different
types for the possible two outcomes, true and false. In fact, if we declare a
class template BoolConstant with the two possible instantiations TrueType
and FalseType: Click here to view code image
traits/boolconstant.hpp
template
struct BoolConstant {
using Type = BoolConstant;
static constexpr bool value = val;
};
using TrueType = BoolConstant;
using FalseType = BoolConstant; we can define IsSameT so that,
depending on whether the two types match, it derives from TrueType or
FalseType: Click here to view code image

traits/issame.hpp
#include "boolconstant.hpp"
template
struct IsSameT : FalseType
{
};
template
struct IsSameT : TrueType
{
};

Now, the resulting type of IsSameT implicitly converts to its base class
TrueType or FalseType, which not only provides the corresponding value
member but also allows us to dispatch to different function implementations or
partial class template specializations at compile time. For example: Click here to
view code image
traits/issame.cpp
#include "issame.hpp"
#include 
template
void fooImpl(T, TrueType)
{
std::cout << "fooImpl(T,true) for int called\n";
}
template
void fooImpl(T, FalseType)
{
std::cout << "fooImpl(T,false) for other type called\n";
}
template
void foo(T t)
{
fooImpl(t, IsSameT{}); // choose impl. depending on whether T
is int
}
int main()
{
foo(42); // calls fooImpl(42, TrueType)
foo(7.7); // calls fooImpl(42, FalseType)
}

This technique is called tag dispatching and is introduced in Section 20.2 on
page 467.
Note that our BoolConstant implementation includes a Type member,
which allows us to reintroduce an alias template for IsSameT: Click here to
view code image
template
using IsSame = typename IsSameT::Type; That alias template can
coexist with the variable template isSame.

In general, traits yielding Boolean values should support tag dispatching by
deriving from types such as TrueType and FalseType. However, to be as
generic as possible, there should be only one type representing true and one
type representing false instead of having each generic library defining its own
types for Boolean constants.
Fortunately, the C++ standard library provides corresponding types in
 since C++11: std::true_type and std::false_type. In C++11
and C++14, they are defined as follows: Click here to view code image
namespace std {
using true_type = integral_constant;
using false_type = integral_constant;
}

Since C++17, they are defined as
Click here to view code image
namespace std {
using true_type = bool_constant;
using false_type = bool_constant;
}

where bool_constant is defined in namespace std as Click here to view
code image
template
using bool_constant = integral_constant; See Section D.1.1
on page 699 for further details.

For this reason, we use std::true_type and std::false_type
directly for the rest of this book, especially when defining type predicates.

19.3.4 Result Type Traits
Another example of type functions that deal with multiple types are result type

traits. They are very useful when writing operator templates. To motivate the
idea, let’s write a function template that allows us to add two Array containers:
Click here to view code image
template
Array operator+ (Array const&, Array const&); This would be
nice, but because the language allows us to add a char value to an
int value, we really would prefer to allow such mixed-type operations
with arrays too. We are then faced with determining what the return
type of the resulting template should be Click here to view code
image
template
Array operator+ (Array const&, Array const&); Besides
the different approaches introduced in Section 1.3 on page 9, a
result type template allows us to fill in the question marks in the
previous declaration as follows: Click here to view code image
template
Array::Type>
operator+ (Array const&, Array const&); or, if we assume the
availability of a convenience alias template, Click here to view code
image
template
Array>
operator+ (Array const&, Array const&); The PlusResultT trait
determines the type produced by adding values of two (possibly
different) types with the + operator: Click here to view code image

traits/plus1.hpp
template
struct PlusResultT {
using Type = decltype(T1() + T2());
};
template
using PlusResult = typename PlusResultT::Type; This trait
template uses decltype to compute the type of the expression T1() +
T2(), leaving the hard work of determining the result type (including
handling promotion rules and overloaded operators) to the compiler.

However, for the purpose of our motivating example, decltype actually
preserves too much information (see Section 15.10.2 on page 298 for a
description of decltype’s behavior). For example, our formulation of
PlusResultT may produce a reference type, but most likely our Array class
template is not designed to handle reference types. More realistically, an
overloaded operator+ might return a value of const class type: Click here
to view code image

class Integer { … };
Integer const operator+ (Integer const&, Integer const&); Adding two
Array values will result in an array of Integer const, which
is most likely not what we intended. In fact, what we want is to
transform the result type by removing references and qualifiers, as
discussed in the previous section: Click here to view code image
template
Array>>>
operator+ (Array const&, Array const&); Such nesting of
traits is common in template libraries and is often used in the
context of metaprogramming. Metaprogramming will be covered in detail
in Chapter 23. (The convenience alias templates are particularly
helpful with multilevel nesting like this. Without them, we’d have to
add a typename and a ::Type suffix at every level.) At this point,
the array addition operator properly computes the result type when
adding two arrays of (possibly different) element types. However, our
formulation of PlusResultT places an undesirable restriction on the
element types T1 and T2: Because the expression T1() + T2() attempts
to value-initialize values of types T1 and T2, both of these types
must have an accessible, nondeleted, default constructor (or be
nonclass types). The Array class itself might not otherwise require
value-initialization of its element type, so this is an additional,
unnecessary restriction.

declval
Fortunately, it is fairly easy to produce values for the + expression without
requiring a constructor, by using a function that produces values of a given type
T. For this, the C++ standard provides std::declval<>, as introduced in
Section 11.2.3 on page 166. It is defined in  simply as follows:
Click here to view code image
namespace std {
template
add_rvalue_reference_t declval() noexcept;
}

The expression declval() produces a value of type T without requiring a
default constructor (or any other operation).
This function template is intentionally left undefined because it’s only meant
to be used within decltype, sizeof, or some other context where no
definition is ever needed. It has two other interesting attributes: • For
referenceable types, the return type is always an rvalue reference to the type,
which allows declval to work even with types that could not normally be
returned from a function, such as abstract class types (classes with pure virtual

functions) or array types. The transformation from T to T&& otherwise has no
practical effect on the behavior of declval() when used as an
expression: Both are rvalues (if T is an object type), while lvalue reference types
are unchanged due to reference collapsing (described in Section 15.6 on page
277).11
• The noexcept exception specification documents that declval itself does
not cause an expression to be considered to throw exceptions. It becomes
useful when declval is used in the context of the noexcept operator
(Section 19.7.2 on page 443).
With declval, we can eliminate the value-initialization requirement for
PlusResultT: Click here to view code image
traits/plus2.hpp
#include 
template
struct PlusResultT {
using Type = decltype(std::declval() + std::declval());
};
template
using PlusResult = typename PlusResultT::Type; Result type
traits offer a way to determine the precise return type of a
particular operation and are often useful when describing the result
types of function templates.

19.4 SFINAE-Based Traits
The SFINAE principle (substitution failure is not an error; see Section 8.4 on
page 129 and Section 15.7 on page 284) turns potential errors during the
formation of invalid types and expressions during template argument deduction
(which would cause the program to be ill-formed) into simple deduction failures,
allowing overload resolution to select a different candidate. While originally
intended to avoid spurious failures with function template overloading, SFINAE
also enables remarkable compile-time techniques that can determine if a
particular type or expression is valid. This allows us to write traits that
determine, for example, whether a type has a specific member, supports a
specific operation, or is a class.
The two main approaches for SFINAE-based traits are to SFINAE out

functions overloads and to SFINAE out partial specializations.

19.4.1 SFINAE Out Function Overloads
Our first foray into SFINAE-based traits illustrates the basic technology using
SFINAE with function overloading to find out whether a type is default
constructible, so that you can create objects without any value for initialization.
That is, for a given type T, an expression such as T() has to be valid.
A basic implementation can look as follows:
Click here to view code image

traits/isdefaultconstructible1.hpp
#include "issame.hpp"
template
struct IsDefaultConstructibleT {
private:
// test() trying substitute call of a default constructor for T passed
as U :
template
static char test(void*);
// test() fallback:
template
static long test(…);
public:
static constexpr bool value
= IsSameT(nullptr)), char>::value;
};

The usual approach to implement a SFINAE-base trait with function overloading
is to declare two overloaded function templates named test() with different
return types: Click here to view code image
template<…> static char test(void*);
template<…> static long test(…); The first overload is designed to
match only if the requested check succeeds (we will discuss below how
that is achieved). The second overload is the fallback:12 It always
matches the call, but because it matches “with ellipsis” (i.e., a
vararg parameter), any other match would be preferred (see Section
C.2 on page 682).

Our “return value” value depends on which overloaded test member is
selected: Click here to view code image

static constexpr bool value
= IsSameT(nullptr)), char>::value; If the first
test() member—whose return type is char—is selected, value will be
initialized to isSame, which is true. Otherwise, it will
be initialized to isSame, which is false.

Now, we have to deal with the specific properties we want to test. The goal is
to make the first test() overload valid if and only if the condition we want to
check applies. In this case, we want to find out whether we can default construct
an object of the passed type T. To achieve this, we pass T as U and give our first
declaration of test() a second unnamed (dummy) template argument
initialized with an construct that is valid if and only if the conversion is valid. In
this case, we use the expression that can only be valid if an implicit or explicit
default constructor exists: U(). The expression is surrounded by decltype to
make this a valid expression to initialize a type parameter.
The second template parameter cannot be deduced, as no corresponding
argument is passed. And we will not provide an explicit template argument for it.
Therefore, it will be substituted, and if the substitution fails, according to
SFINAE, that declaration of test() will be discarded so that only the fallback
declaration will match.
Thus, we can use the trait as follows:
Click here to view code image
IsDefaultConstructibleT::value //yields true
struct S {
S() = delete;
};
IsDefaultConstructibleT::value //yields false

Note that we can’t use the template parameter T in the first test() directly:
Click here to view code image
template
struct IsDefaultConstructibleT {
private:
// ERROR: test() uses T directly:
template
static char test(void*);
// test() fallback:
template
static long test(…);
public:
static constexpr bool value
= IsSameT(nullptr)), char>::value;
};

This doesn’t work, however, because for any T, always, all member functions
are substituted, so that for a type that isn’t default constructible, the code fails to
compile instead of ignoring the first test() overload. By passing the class
template parameter T to a function template parameter U, we create a specific
SFINAE context only for the second test() overload.
Alternative Implementation Strategies for SFINAE-based Traits
SFINAE-based traits have been possible to implement since before the first C++
standard was published in 1998.13 The key to the approach always consisted in
declaring two overloaded function templates returning different return types:
Click here to view code image
template<…> static char test(void*);
template<…> static long test(…); However, the original published
technique14 used the size of the return type to determine which
overload was selected (also using 0 and enum, because nullptr and
constexpr were not available): Click here to view code image
enum { value = sizeof(test<…>(0)) == 1 }; On some platforms, it might
happen that sizeof(char)==sizeof(long). For example, on digital
signal processors (DSP) or old Cray machines, all integral
fundamental types could have the same size. As by definition
sizeof(char) equals 1, on those machines sizeof(long) and even
sizeof(long long) also equal 1.

Given that observation, we want to ensure that the return types of the test()
functions have different sizes on all platforms. For example, after defining Click
here to view code image
using Size1T = char;
using Size2T = struct { char a[2]; }; or
Click here to view code image
using Size1T = char(&)[1];
using Size2T = char(&)[2]; we could define test test() overloads as
follows: Click here to view code image
template<…> static Size1T test(void*); // checking test()
template<…> static Size2T test(…); // fallback

Here, we either return a Size1T, which is a single char of size 1, or we return
(a structure of) an array of two chars, which has a size of at least 2 on all
platforms.
Code using one of these approaches is still commonly found.
Note also that the type of the call argument passed to func() doesn’t matter.

All that matters is that the passed argument matches the expected type. For
example, you could also define to pass the integer 42: Click here to view code
image
template<…> static Size1T test(int); // checking test()
template<…> static Size2T test(…); // fallback
…
enum { value = sizeof(test<…>(42)) == 1 };

Making SFINAE-based Traits Predicate Traits
As introduced in Section 19.3.3 on page 410, a predicate trait, which returns a
Boolean value, should return a value derived from std::true_type or
std::false_type. This way, we can also solve the problem that on some
platforms sizeof(char)==sizeof(long).
For this, we need an indirect definition of IsDefaultConstructibleT.
The trait itself should derive from the Type of a helper class, which yields the
necessary base class. Fortunately, we can simply provide the corresponding base
classes as return types of the test() overloads: Click here to view code image
template<…> static std::true_type test(void*); // checking test()
template<…> static std::false_type test(…); // fallback

That way, the Type member for the base class simply can be declared as
follows: Click here to view code image
using Type = decltype(test(nullptr)); and we no longer need the
IsSameT trait.

The complete improved implementation of IsDefaultConstructibleT
therefore becomes as follows: Click here to view code image
traits/isdefaultconstructible2.hpp
#include 
template
struct IsDefaultConstructibleHelper {
private:
// test() trying substitute call of a default constructor for T passed
as U:
template
static std::true_type test(void*);
// test() fallback:
template
static std::false_type test(…);
public:

using Type = decltype(test(nullptr));
};
template
struct IsDefaultConstructibleT : IsDefaultConstructibleHelper::Type
{
};

Now, if the first test() function template is valid, it is the preferred overload,
so that the member IsDefaultConstructibleHelper::Type is
initialized by its return type std::true_type. As a consequence,
IsConvertibleT<… > derives from std::true_type.
If the first test() function template is not valid, it becomes disabled due to
SFINAE, and IsDefaultConstructibleHelper::Type is initialized
by the return type of the test() fall-back, that is, std::false_type. The
effect is that IsConvertibleT<… > then derives from
std::false_type.

19.4.2 SFINAE Out Partial Specializations
The second approach to implement SFINAE-based traits uses partial
specialization. Again, we can use the example to find out whether a type T is
default constructible: Click here to view code image
traits/isdefaultconstructible3.hpp
#include "issame.hpp"
#include  //defines true_type and false_type
// helper to ignore any number of template parameters:
template using VoidT = void;
// primary template:
template>
struct IsDefaultConstructibleT : std::false_type
{
};
// partial specialization (may be SFINAE’d away):
template
struct IsDefaultConstructibleT> :
std::true_type
{
};

As with the improved version of IsDefaultConstructibleT for predicate
traits above, we define the general case to be derived from
std::false_type, because by default a type doesn’t have the member
size_type.
The interesting feature here is the second template argument that defaults to
the type of a helper VoidT. It enables us to provide partial specializations that
use an arbitrary number of compile-time type constructs.
In this case, we need only one construct:
decltype(T()) to check again whether the default constructor for T is
valid. If, for a specific T, the construct is invalid, SFINAE this
time causes the whole partial specialization to be discarded, and we
fall back to the primary template. Otherwise, the partial
specialization is valid and preferred.

In C++17, the C++ standard library introduced a type trait std::void_t<>
that corresponds to the type VoidT introduced here. Before C++17, it might be
helpful to define it ourselves as above or even in namespace std as follows:15
Click here to view code image
#include 
#ifndef __cpp_lib_void_t
namespace std {
template using void_t = void;
}
#endif

Starting with C++14, the C++ standardization committee has recommended that
compilers and standard libraries indicate which parts of the standard they have
implemented by defining agreed-upon feature macros. This is not a
requirement for standard conformance, but implementers typically follow
the recommendation to be helpful to their users.16 The macro
__cpp_lib_void_t is the macro recommended to indicate that a library
implements std::void_t, and thus our code above is made conditional on it.
Obviously, this way to define a type trait looks more condensed that the first
approach to overload function templates. But it requires the ability to formulate
the condition inside the declaration of a template parameter. Using a class
template with function overloads enables us to use additional helper functions or
helper types.

19.4.3 Using Generic Lambdas for SFINAE

Whichever technique we use, some boilerplate code is always needed to define
traits: overloading and calling two test() member functions or implementing
multiple partial specializations. Next, we will show how in C++17, we can
minimize this boilerplate by specifying the condition to be checked in a generic
lambda.17
To start with, we introduce a tool constructed from two nested generic lambda
expressions: Click here to view code image
traits/isvalid.hpp
#include 
// helper: checking validity of f (args…) for F f and Args… args:
template()(std::declval()…))>
std::true_type isValidImpl(void*);
// fallback if helper SFINAE’d out:
template
std::false_type isValidImpl(…);
// define a lambda that takes a lambda f and returns whether calling f
with args is valid
inline constexpr
auto isValid = [](auto f) {
return [](auto&&… args) {
return decltype(isValidImpl(nullptr)){};
};
};
// helper template to represent a type as a value
template
struct TypeT {
using Type = T;
};
// helper to wrap a type as a value
template
constexpr auto type = TypeT{};
// helper to unwrap a wrapped type in unevaluated contexts
template
T valueT(TypeT); // no definition needed

Let’s start with the definition of isValid: It is a constexpr variable whose

type is a lambda’s closure type. The declaration must necessarily use a
placeholder type (auto in our code) because C++ has no way to express closure
types directly. Prior to C++17, lambda expressions could not appear in constantexpressions, which is why this code is only valid in C++17. Since isValid has
a closure type, it can be invoked (i.e., called), but the item that it returns is itself
an object of a lambda closure type, produced by the inner lambda expression.
Before delving into the details of that inner lambda expression, let’s examine a
typical use of isValid: Click here to view code image
constexpr auto isDefaultConstructible
= isValid([](auto x) -> decltype((void)decltype(valueT(x))() {
});

We already know that isDefaultConstructible has a lambda closure
type and, as the name suggests, it is a function object that checks the trait of a
type being default-constructible (we’ll see why in what follows). In other words,
isValid is a traits factory: A component that generates traits checking objects
from its argument.
The type helper variable template allows us to represent a type as a value. A
value x obtained that way can be turned back into the original type with
decltype(valueT(x))18, and that’s exactly what is done in the lambda
passed to isValid above. If that extracted type cannot be default-constructed,
decltype(valueT(x))() is invalid, and we will either get a compiler
error, or an associated declaration will be “SFINAE’d out” (and the latter effect
is what we’ll achieve thanks to the details of the definition of isValid).
isDefaultConstructible can be used as follows: Click here to view
code image
isDefaultConstructible(type) //true (int is defaultconstructible)
isDefaultConstructible(type) //false (references are not
default-constructible)

To see how all the pieces work together, consider what the inner lambda
expression in isValid becomes with isValid’s parameter f bound to the
generic lambda argument specified in the definition of
isDefaultConstructible. By performing the substitution in isValid’s
definition, we get the equivalent of:19
Click here to view code image
constexpr auto isDefaultConstructible
= [](auto&&… args) {
return decltype(

isValidImpl<
decltype([](auto x)
-> decltype((void)decltype(valueT(x))())),
decltype(args)&&…
>(nullptr)){};
};

If we look back at the first declaration of isValidImpl() above, we note that
it includes a default template argument of the form Click here to view code
image
decltype(std::declval()(std::declval()…))> which attempts
to invoke a value of the type of its first template argument, which
is the closure type of the lambda in the definition of
isDefaultConstructible, with values of the types of the arguments
(decltype(args)&&…) passed to isDefaultConstructible. As there is
only one parameter x in the lambda, args must expand to only one
argument; in our static_assert examples above, that argument has type
TypeT or TypeT. In the TypeT case,
decltype(valueT(x)) is int& which makes decltype(valueT(x))()
invalid, and thus the substitution of the default template argument
in the first declaration of isValidImpl() fails and is SFINAE’d out.
That leaves just the second declaration (which would otherwise be a
lesser match), which produces a false_type value. Overall,
isDefaultConstructible produces false_type when type is passed.
If instead type is passed, the substitution does not fail, and
the first declaration of isValidImpl() is selected, producing a
true_type value.

Recall that for SFINAE to work, substitutions have to happen in the
immediate context of the substituted templates. In this case, the substituted
templates are the first declaration of isValidImpl and the call operator of the
generic lambda passed to isValid. Therefore, the construct to be tested has to
appear in the return type of that lambda, not in its body!
Our isDefaultConstructible trait is a little different from previous
traits implementations in that it requires function-style invocation instead of
specifying template arguments. That is arguably a more readable notation, but
the prior style can be obtained also: Click here to view code image
template
using IsDefaultConstructibleT
= decltype(isDefaultConstructible(std::declval())); Since this is
a traditional template declaration, however, it can only appear in
namespace scope, whereas the definition of isDefaultConstructible
could conceivably have been introduced in block scope.

So far, this technique might not seem compelling because both the expressions
involved in the implementation and the style of use are more complex than the
previous techniques. However, once isValid is in place and understood, many

traits can be implement with just one declaration. For example, testing for access
to a member named first, is rather clean (see Section 19.6.4 on page 438 for
the complete example): Click here to view code image
constexpr auto hasFirst
= isValid([](auto x) -> decltype((void)valueT(x).first) {
});

19.4.4 SFINAE-Friendly Traits
In general, a type trait should be able to answer a particular query without
causing the program to become ill-formed. SFINAE-based traits address this
problem by carefully trapping potential problems within a SFINAE context,
turning those would-be errors into negative results.
However, some traits presented thus far (such as the PlusResultT trait
described in Section 19.3.4 on page 413) do not behave well in the presence of
errors. Recall the definition of PlusResultT from that section: Click here to
view code image
traits/plus2.hpp
#include 
template
struct PlusResultT {
using Type = decltype(std::declval() + std::declval());
};
template
using PlusResult = typename PlusResultT::Type; In this
definition, the + is used in a context that is not protected by
SFINAE. Therefore, if a program attempts to evaluate PlusResultT for
types that do not have a suitable + operator, the evaluation of
PlusResultT itself will cause the program to become ill-formed, as in
the following attempt to declare the return type of adding arrays of
unrelated types A and B:20
Click here to view code image
template
class Array {
…
};
// declare + for arrays of different element types:

template
Array::Type>
operator+ (Array const&, Array const&); Clearly, using
PlusResultT<> here will lead to an error if no corresponding operator
+ is defined for the array element.
Click here to view code image
class A {
};
class B {
};
void addAB(Array arrayA, Array arrayB) {
auto sum = arrayA + arrayB; // ERROR: fails in instantiation of
PlusResultT
…
}

The practical problem is not that this failure occurs with code that is clearly illformed like this (there is no way to add an array of A to an array of B) but that it
occurs during template argument deduction for operator+, deep in the
instantiation of PlusResultT.
This has a remarkable consequence: It means that the program may fail to
compile even if we add a specific overload to adding A and B arrays, because
C++ does not specify whether the types in a function template are actually
instantiated if another overload would be better: Click here to view code image
// declare generic + for arrays of different element types:
template
Array::Type>
operator+ (Array const&, Array const&);
// overload + for concrete types:
Array operator+(Array const& arrayA, Array const& arrayB);
void addAB(Array const& arrayA, Array const& arrayB) {
auto sum = arrayA + arrayB; // ERROR?: depends on whether the
compiler
… // instantiates PlusResultT
}

If the compiler can determine that the second declaration of operator+ is a
better match without performing deduction and substitution on the first
(template) declaration of operator+, it will accept this code.
However, while deducing and substituting a function template candidate,
anything that happens during the instantiation of the definition of a class
template is not part of the immediate context of that function template

substitution, and SFINAE does not protect us from attempts to form invalid
types or expressions there. Instead of just discarding the function template
candidate, an error is issued right away because we try to call operator+ for
two elements of types A and B inside PlusResultT<>: Click here to view
code image
template
struct PlusResultT {
using Type = decltype(std::declval() + std::declval());
};

To solve this problem, we have to make the PlusResultT SFINAE-friendly,
which means to make it more resilient by giving it a suitable definition even
when its decltype expression is ill-formed.
Following the example of HasLessT described in the previous section, we
define a HasPlusT trait that allows us to detect whether there is a suitable +
operation for the given types: Click here to view code image
traits/hasplus.hpp
#include  // for declval
#include  // for true_type, false_type, and void_t
// primary template:
template>
struct HasPlusT : std::false_type
{
};
// partial specialization (may be SFINAE’d away):
template
struct HasPlusT()
+ std::declval())>>
: std::true_type
{
};

If it yields a true result, PlusResultT can use the existing implementation.
Otherwise, PlusResultT needs a safe default. The best default for a trait that
has no meaningful result for a set of template arguments is to not provide any
member Type at all. That way, if the trait is used within a SFINAE context—
such as the return type of the array operator+ template above—the missing
member Type will make template argument deduction fail, which is precisely
the behavior desired for the array operator+ template.
The following implementation of PlusResultT provides this behavior:

Click here to view code image
traits/plus3.hpp
#include "hasplus.hpp"
template::value>
struct PlusResultT { //primary template, used when HasPlusT yields
true
using Type = decltype(std::declval() + std::declval());
};
template
struct PlusResultT { //partial specialization, used
otherwise
};

In this version of PlusResultT, we add a template parameter with a default
argument that determines if the first two parameters support addition as
determined by our HasPlusT trait above. We then partially specialize
PlusResultT for false values of that extra parameter, and our partial
specialization definition has no members at all, avoiding the problems we
described. For cases where addition is supported, the default argument evaluates
to true and the primary template is selected, with our existing definition of the
Type member. Thus, we fulfill the contract that PlusResultT provide the
result type only if in fact the + operation is well-formed. (Note that the added
template parameter should never have an explicit template argument.) Consider
again the addition of Array and Array: With our latest
implementation of the PlusResultT template, the instantiation of
PlusResultT will not have a Type member, because A and B values
are not addable. Therefore, the result type of the array operator+ template is
invalid, and SFINAE will eliminate the function template from consideration.
The overloaded operator+ that is specific to Array and Array
will therefore be chosen.
As a general design principle, a trait template should never fail at instantiation
time if given reasonable template arguments as inputs. And the general approach
is often to perform the corresponding check twice: 1. Once to find out whether
the operation is valid 2. Once to to compute its result We saw that already with
PlusResultT, where we call HasPlusT<> to find out whether the call of
operator+ in PlusResultImpl<> is valid.
Let’s apply this principle to ElementT as introduced in Section 19.3.1 on
page 401: It produces an element type from a container type. Again, since the

answer relies on a (container) type having a member type value_type, the
primary template should attempt to define the member Type only when the
container type has such a value_type member: Click here to view code
image
template::value>
struct ElementT {
using Type = typename C::value_type;
};
template
struct ElementT {
};

A third example of making traits SFINAE-friendly is shown Section 19.7.2 on
page 444, where IsNothrowMoveConstructibleT first has to check
whether a move constructor exists before checking whether it is declared with
noexcept.

19.5 IsConvertibleT
Details matter. And for that reason, the general approach for SFINAE-based
traits might become more complicated in practice. Let’s illustrate this by
defining a trait that can determine whether a given type is convertible to another
given type—for example, if we expect a certain base class or one of its derived
classes. The IsConvertibleT trait yields whether we can convert a passed
first type to a passed second type: Click here to view code image
traits/isconvertible.hpp
#include  // for true_type and false_type
#include  // for declval
template
struct IsConvertibleHelper {
private:
// test() trying to call the helper aux(TO) for a FROM passed as F :
static void aux(TO);
template()))>
static std::true_type test(void*);
// test() fallback:
template
static std::false_type test(…);
public:

using Type = decltype(test(nullptr));
};
template
struct IsConvertibleT : IsConvertibleHelper::Type {
};
template
using IsConvertible = typename IsConvertibleT::Type;
template
constexpr bool isConvertible = IsConvertibleT::value; Here,
we use the approach with function overloading, as introduced in
Section 19.4.1 on page 416. That is, inside a helper class we declare
two overloaded function templates named test() with different return
types and declare a Type member for the base class of the resulting
trait: Click here to view code image
template<…> static std::true_type test(void*);
template<…> static std::false_type test(…);
…
using Type = decltype(test(nullptr));
…
template
struct IsConvertibleT : IsConvertibleHelper::Type {
};

As usual, the first test() overload is designed to match only if the requested
check succeeds, while the second overload is the fallback. Thus, the goal is to
make the first test() overload valid if and only if type FROM converts to type
TO. To achieve this, again we give our first declaration of test a dummy
(unnamed) template argument initialized with a construct that is valid if and only
if the conversion is valid. This template parameter cannot be deduced, and we
will not provide an explicit template argument for it. Therefore, it will be
substituted, and if the substitution fails, that declaration of test() will be
discarded.
Again, note that the following doesn’t work:
Click here to view code image
static void aux(TO);
template()))>
static char test(void*); Here, FROM and TO are completely determined
when this member function template is parsed, and therefore a pair of
types for which the conversion is not valid (e.g., double* and int*)
will trigger an error right away, before any call to test() (and
therefore outside any SFINAE context).

For that reason, we introduce F as a specific member function template

parameter Click here to view code image
static void aux(TO);
template()))>
static char test(void*); and provide the FROM type as an explicit
template argument in the call to test() that appears in the
initialization of value: Click here to view code image
static constexpr bool value
= isSame(nullptr)), char>; Note how std::declval,
introduced in Section 19.3.4 on page 415, is used to produce a value
without calling any constructor. If that value is convertible to TO,
the call to aux() is valid, and this declaration of test() matches.
Otherwise, a SFINAE failure occurs and only the fallback declaration
will match.

As a result, we can use the trait as follows: Click here to view code image
IsConvertibleT::value //yields true
IsConvertibleT::value //yields false
IsConvertibleT::value //yields true
IsConvertibleT::value //yields false

Handling Special Cases
Three cases are not yet handled correctly by IsConvertibleT: 1.
Conversions to array types should always yield false, but in our code, the
parameter of type TO in the declaration of aux() will just decay to a pointer
type and therefore enable a “true” result for some FROM types.
2. Conversions to function types should always yield false, but just as with the
array case, our implementation just treats them as the decayed type.
3. Conversion to (const/volatile-qualified) void types should yield
true. Unfortunately, our implementation above doesn’t even successfully
instantiate the case where TO is a void type because parameter types cannot
have type void (and aux() is declared with such a parameter).
For all these cases, we’ll need additional partial specializations. However,
adding such specializations for every possible combination of const and
volatile qualifiers quickly becomes unwieldy. Instead, we can add an
additional template parameter to our helper class template as follows: Click here
to view code image
template::value
|| IsArrayT::value
|| IsFunctionT::value>
struct IsConvertibleHelper {
using Type = std::integral_constant::value
&& IsVoidT::value>;
};
template
struct IsConvertibleHelper {
… //previous implementation of IsConvertibleHelper here
};

The extra Boolean template parameter ensures that for all these special cases the
implementation of the primary helper trait is used. It yields false_type if we
convert to arrays or functions (because then IsVoidT is false) or if FROM
is void and TO is not, but for two void types it will produce false_type.
All other cases produce a false argument for the third parameter and therefore
pick up the partial specialization, which corresponds to the implementation we
already discussed.
See Section 19.8.2 on page 453 for a discussion of how to implement
IsArrayT and Section 19.8.3 on page 454 for a discussion of how to
implement IsFunctionT.
The C++ standard library provides a corresponding type trait
std::is_convertible<>, which is described in Section D.3.3 on page
727.

19.6 Detecting Members
Another foray into SFINAE-based traits involves creating a trait (or, rather, a set
of traits) that can determine whether a given type T has a member of a given
name X (a type or a nontype member).

19.6.1 Detecting Member Types
Let’s first define a trait that can determine whether a given type T has a member
type size_type: Click here to view code image
traits/hassizetype.hpp
#include  // defines true_type and false_type
// helper to ignore any number of template parameters:
template using VoidT = void;

// primary template:
template>
struct HasSizeTypeT : std::false_type
{
};
// partial specialization (may be SFINAE’d away):
template
struct HasSizeTypeT> : std::true_type
{
};

Here, we use the approach to SFINAE out partial specializations introduced in
Section 19.4.2 on page 420.
As usual for predicate traits, we define the general case to be derived from
std::false_type, because by default a type doesn’t have the member
size_type.
In this case, we only need one construct:
typename T::size_type This construct is valid if and only if type T
has a member type size_type, which is exactly what we are trying to
determine. If, for a specific T, the construct is invalid (i.e., type
T has no member type size_type), SFINAE causes the partial
specialization to be discarded, and we fall back to the primary
template. Otherwise, the partial specialization is valid and
preferred.

We can use the trait as follows:
Click here to view code image
std::cout << HasSizeTypeT::value; // false
struct CX {
using size_type = std::size_t;
};
std::cout << HasSizeType::value; // true

Note that if the member type size_type is private, HasSizeTypeT yields
false because our traits templates have no special access to their argument
type, and therefore typename T::size_type is invalid (i.e., triggers
SFINAE). In other words, the trait tests whether we have an accessible member
type size_type.
Dealing with Reference Types
As programmers, we are familiar with the surprises that can arise “on the edges”

of the domains we consider. With a traits template like HasSizeTypeT,
interesting issues can arise with reference types. For example, while the
following works fine: Click here to view code image
struct CXR {
using size_type = char&; // Note: type size_type is a reference type
};
std::cout << HasSizeTypeT::value; // OK: prints true

the following fails:
Click here to view code image
std::cout << HasSizeTypeT::value; // OOPS: prints false
std::cout << HasSizeTypeT::value; // OOPS: prints false

and that is potentially surprising. It is true that a reference type has not members
per se, but whenever we use references, the resulting expressions have the
underlying type, and so perhaps it would be preferable to consider the
underlying type in that case. Here, that could be achieved by using our earlier
RemoveReference trait in the partial specialization of HasSizeTypeT:
Click here to view code image
template
struct HasSizeTypeT::size_type>>
: std::true_type {
};

Injected Class Names
It’s also worth noting that our traits technique to detect member types will also
produce a true value for injected class names (see Section 13.2.3 on page 221).
For example: Click here to view code image
struct size_type {
};
struct Sizeable : size_type {
};
static_assert(HasSizeTypeT::value,
"Compiler bug: Injected class name missing"); The latter static
assertion succeeds because size_type introduces its own name as a
member type, and that name is inherited. If it didn’t succeed, we
would have found a defect in the compiler.

19.6.2 Detecting Arbitrary Member Types

Defining a trait such as HasSizeTypeT raises the question of how to
parameterize the trait to be able to check for any member type name.
Unfortunately, this can currently be achieved only via macros, because there is
no language mechanism to describe a “potential” name.21 The closest we can get
for the moment without using macros is to use generic lambdas, as illustrated in
Section 19.6.4 on page 438.
The following macro would work:
Click here to view code image

traits/hastype.hpp
#include  // for true_type, false_type, and void_t
#define DEFINE_HAS_TYPE(MemType) \
template> \
struct HasTypeT_##MemType \
: std::false_type { }; \
template \
struct HasTypeT_##MemType> \
: std::true_type { } // ; intentionally skipped

Each use of DEFINE_HAS_TYPE(MemberType) defines a new
HasTypeT_MemberType trait. For example, we can use it to detect whether a
type has a value_type or a char_type member type as follows: Click here
to view code image
traits/hastype.cpp
#include "hastype.hpp"
#include 
#include 
DEFINE_HAS_TYPE(value_type);
DEFINE_HAS_TYPE(char_type);
int main()
{
std::cout << "int::value_type: "
<< HasTypeT_value_type::value << ’\n’;
std::cout << "std::vector::value_type: "
<< HasTypeT_value_type>::value << ’\n’;
std::cout << "std::iostream::value_type: "
<< HasTypeT_value_type::value << ’\n’;
std::cout << "std::iostream::char_type: "
<< HasTypeT_char_type::value << ’\n’;
}

19.6.3 Detecting Nontype Members
We can modify the trait to also check for data members and (single) member
functions: Click here to view code image
traits/hasmember.hpp
#include  // for true_type, false_type, and void_t
#define DEFINE_HAS_MEMBER(Member) \
template> \
struct HasMemberT_##Member \
: std::false_type { }; \
template \
struct HasMemberT_##Member> \
: std::true_type { } // ; intentionally skipped

Here, we use SFINAE to disable the partial specialization when &T::Member
is not valid. For that construct to be valid, the following must be true: • Member
must unambiguously identify a member of T (e.g., it cannot be an overloaded
member function name, or the name of multiple inherited members of the same
name), • The member must be accessible,
• The member must be a nontype, nonenumerator member (otherwise the prefix
& would be invalid), and • If T::Member is a static data member, its type
must not provide an operator& that makes &T::Member invalid (e.g., by
making that operator inaccessible). We can use the template as follows: Click
here to view code image
traits/hasmember.cpp
#include "hasmember.hpp"
#include 
#include 
#include 
DEFINE_HAS_MEMBER(size);
DEFINE_HAS_MEMBER(first);
int main()
{
std::cout << "int::size: "
<< HasMemberT_size::value << ’\n’;

std::cout << "std::vector::size: "
<< HasMemberT_size>::value << ’\n’;
std::cout << "std::pair::first: "
<< HasMemberT_first>::value << ’\n’;
}

It would not be difficult to modify the partial specialization to exclude cases
where &T::Member is not a pointer-to-member type (which amounts to
excluding static data members). Similarly, a pointer-to-member function could
be excluded or required to limit the trait to data members or member functions.
Detecting Member Functions
Note that the HasMember trait only checks whether a single member with the
corresponding name exists. The trait also will fail if two members exists, which
might happen if we check for overloaded member functions. For example: Click
here to view code image
DEFINE_HAS_MEMBER(begin);
std::cout << HasMemberT_begin>::value; // false

However, as explained in Section 8.4.1 on page 133, the SFINAE principle
protects against attempts to create both invalid types and expressions in a
function template declaration, allowing the overloading technique above to
extend to testing whether arbitrary expressions are well-formed.
That is, we can simply check whether we can call a function of interest in a
specific way and that can succeed even if the function is overloaded. As with the
IsConvertibleT trait in Section 19.5 on page 428, the trick is to formulate
the expression that checks whether we can call begin() inside a decltype
expression for the default value of an additional function template parameter:
Click here to view code image
traits/hasbegin.hpp
#include  // for declval
#include  // for true_type, false_type, and void_t
// primary template:
template>
struct HasBeginT : std::false_type {
};
// partial specialization (may be SFINAE’d away):
template
struct HasBeginT().begin())>>

: std::true_type {
};

Here, we use
Click here to view code image
decltype(std::declval().begin()) to test whether, given a
value/object of type T (using std::declval to avoid any constructor
being required), calling a member begin() is valid.22

Detecting Other Expressions
We can use the technique above for other kinds of expressions and even combine
multiple expressions. For example, we can test whether, given types T1 and T2,
there is a suitable < operator defined for values of these types: Click here to view
code image
traits/hasless.hpp
#include  // for declval
#include  // for true_type, false_type, and void_t
// primary template:
template>
struct HasLessT : std::false_type
{
};
// partial specialization (may be SFINAE’d away):
template
struct HasLessT()
())>>
: std::true_type
{
};

As always, the challenge is to define a valid expression for the condition to
check and use decltype to place it in a SFINAE context, where it will cause a
fallback to the primary template if the expression isn’t valid: Click here to view
code image
decltype(std::declval() < std::declval()) Traits that detect
valid expressions in this manner are fairly robust: They will
evaluate true only when the expression is well-formed and will
correctly return false when the < operator is ambiguous, deleted, or
inaccessible.23

We can use the trait as follows:
Click here to view code image
HasLessT::value //yields true
HasLessT::value //yields true
HasLessT::value //yields false
HasLessT::value //yields true
HasLessT, std::complex>::value //yields
false

As introduced in Section 2.3.1 on page 30, we can use this trait to require that a
template parameter T supports operator <: Click here to view code image
template
class C
{
static_assert(HasLessT::value,
"Class C requires comparable elements");
…
};

Note that, due to the nature of std::void_t, we can combine multiple
constraints in a trait: Click here to view code image
traits/hasvarious.hpp
#include  // for declval
#include  // for true_type, false_type, and void_t
// primary template:
template>
struct HasVariousT : std::false_type
{
};
// partial specialization (may be SFINAE’d away):
template
struct HasVariousT().begin()),
typename T::difference_type,
typename T::iterator>>
: std::true_type
{
};

Traits that detect the validity of a specific syntax are quite powerful, allowing a
template to customize its behavior based on the presence or absence of a
particular operation. These traits will be used again both as part of the definition
of SFINAE-friendly traits (Section 19.4.4 on page 424) and to aid in overloading
based on type properties (Chapter 20).

19.6.4 Using Generic Lambdas to Detect Members
The isValid lambda, introduced in Section 19.4.3 on page 421, provides a
more compact technique to define traits that check for members, helping is to
avoid the use of macros to handle members if arbitrary names.
The following example illustrates how to define traits checking whether a data
or type member such as first or size_type exists or whether operator<
is defined for two objects of different types: Click here to view code image
traits/isvalid1.cpp
#include "isvalid.hpp"
#include
#include
#include
int main()
{
using namespace std;
cout << boolalpha;
// define to check for data member first:
constexpr auto hasFirst
= isValid([](auto x) -> decltype((void)valueT(x).first) {
});
cout << "hasFirst: " << hasFirst(type>) << ’\n’; // true
// define to check for member type size_type:
constexpr auto hasSizeType
= isValid([](auto x) -> typename decltype(valueT(x))::size_type {
});
struct CX {
using size_type = std::size_t;
};
cout << "hasSizeType: " << hasSizeType(type) << ’\n’; // true
if constexpr(!hasSizeType(type)) {
cout << "int has no size_type\n";
…
}
// define to check for <:
constexpr auto hasLess
= isValid([](auto x, auto y) -> decltype(valueT(x) < valueT(y)) {
});

cout
cout
cout
cout
}

<<
<<
<<
<<

hasLess(42, type) << ’\n’; //yields true
hasLess(type, type) << ’\n’; //yields true
hasLess(type, type) << ’\n’; //yields false
hasLess(type, "hello") << ’\n’; //yields true

Note again that hasSizeType uses std::decay to remove the references
from the passed x because you can’t access a type member from a reference. If
you skip that, the traits will always yield false because the second overload of
isValidImpl<>() is used.
To be able to use the common generic syntax, taking types as template
parameters, we can again define additional helpers. For example: Click here to
view code image
traits/isvalid2.cpp
#include "isvalid.hpp"
#include
#include
#include
constexpr auto hasFirst
= isValid([](auto&& x) -> decltype((void)&x.first) {
});
template
using HasFirstT = decltype(hasFirst(std::declval()));
constexpr auto hasSizeType
= isValid([](auto&& x)
-> typename std::decay_t::size_type {
});
template
using HasSizeTypeT = decltype(hasSizeType(std::declval()));
constexpr auto hasLess
= isValid([](auto&& x, auto&& y) -> decltype(x < y) {
});
template
using HasLessT = decltype(hasLess(std::declval(), std::declval
()));
int main()
{
using namespace std;
cout << "first: " << HasFirstT>::value << ’\n’; // true
struct CX {

using size_type = std::size_t;
};
cout << "size_type: " << HasSizeTypeT::value << ’\n’; // true
cout << "size_type: " << HasSizeTypeT::value << ’\n’; // false
cout
cout
cout
cout
}

<<
<<
<<
<<

HasLessT::value << ’\n’; // true
HasLessT::value << ’\n’; // true
HasLessT::value << ’\n’; // false
HasLessT::value << ’\n’; // true

Now
Click here to view code image
template
using HasFirstT = decltype(hasFirst(std::declval())); allows us to
call
Click here to view code image
HasFirstT>::value which results in the call of
hasFirst for a pair of two ints, which is evaluated as described
above.

19.7 Other Traits Techniques
Let’s finally introduce and discuss some other approaches to define traits.

19.7.1 If-Then-Else
In the previous section, the final definition of the PlusResultT trait had a
completely different implementation depending on the result of another type
trait, HasPlusT. We can formulate this if-then-else behavior with a special type
template IfThenElse that takes a Boolean nontype template parameter to
select one of two type parameters: Click here to view code image
traits/ifthenelse.hpp
#ifndef IFTHENELSE_HPP
#define IFTHENELSE_HPP
// primary template: yield the second argument by default and rely on
// a partial specialization to yield the third argument
// if COND is false

template
struct IfThenElseT {
using Type = TrueType;
};
// partial specialization: false yields third argument
template
struct IfThenElseT {
using Type = FalseType;
};
template
using IfThenElse = typename IfThenElseT::Type;
#endif //IFTHENELSE_HPP

The following example demonstrates an application of this template by defining
a type function that determines the lowest-ranked integer type for a given value:
Click here to view code image
traits/smallestint.hpp
#include 
#include "ifthenelse.hpp"
template
struct SmallestIntT {
using Type =
typename IfThenElseT::Type
>::Type
>::Type
>::Type
>::Type;
};

<=
<=
<=
<=
<=

std::numeric_limits ::max(), char,
std::numeric_limits ::max(), short,
std::numeric_limits ::max(), int,
std::numeric_limits ::max(), long,
std::numeric_limits ::max(),

Note that, unlike a normal C++ if-then-else statement, the template arguments
for both the “then” and “else” branches are evaluated before the selection is
made, so neither branch may contain ill-formed code, or the program is likely to
be ill-formed. Consider, for example, a trait that yields the corresponding
unsigned type for a given signed type. There is a standard trait,
std::make_unsigned, which does this conversion, but it requires that the

passed type is a signed integral type and no bool; otherwise its use results in
undefined behavior (see Section D.4 on page 729). So it might be a good idea to
implement a trait that yields the corresponding unsigned type if this is possible
and the passed type otherwise (thus, avoiding undefined behavior if an
inappropriate type is given). The naive implementation does not work: Click
here to view code image
// ERROR: undefined behavior if T is bool or no integral type:
template
struct UnsignedT {
using Type = IfThenElse::value
&& !std::is_same::value,
typename std::make_unsigned::type,
T>;
};

The instantiation of UnsignedT is still undefined behavior, because
the compiler will still attempt to form the type from Click here to view code
image
typename std::make_unsigned::type To address this problem, we need
to add an additional level of indirection, so that the IfThenElse
arguments are themselves uses of type functions that wrap the result:
Click here to view code image
// yield T when using member Type:
template
struct IdentityT {
using Type = T;
};
// to make unsigned after IfThenElse was evaluated:
template
struct MakeUnsignedT {
using Type = typename std::make_unsigned::type;
};
template
struct UnsignedT {
using Type = typename IfThenElse::value
&& !std::is_same::value,
MakeUnsignedT,
IdentityT
>::Type;
};

In this definition of UnsignedT, the type arguments to IfThenElse are both
instances of type functions themselves. However, the type functions are not
actually evaluated before IfThenElse selects one. Instead, IfThenElse

selects the type function instance (of either MakeUnsignedT or
IdentityT). The ::Type then evaluates the selected type function instance
to produce Type.
It is worth emphasizing here that this relies entirely on the fact that the notselected wrapper type in the IfThenElse construct is never fully instantiated.
In particular, the following does not work: Click here to view code image
template
struct UnsignedT {
using Type = typename IfThenElse::value
&& !std::is_same::value,
MakeUnsignedT::Type,
T
>::Type;
};

Instead, we have to apply the ::Type for MakeUnsignedT later, which
means that we need the IdentityT helper to also apply ::Type later for T in
the else branch.
This also means that we cannot use something like
Click here to view code image
template
using Identity = typename IdentityT::Type; in this context. We can
declare such an alias template, and it may be useful elsewhere, but
we cannot make effective use of it in the definition of IfThenElse
because any use of Identity immediately causes the full
instantiation of IdentityT to retrieve its Type member.

The IfThenElseT template is available in the C++ standard library as
std::conditional<> (see Section D.5 on page 732). With it, the
UnsignedT trait would be defined as follows: Click here to view code image
template
struct UnsignedT {
using Type
= typename std::conditional_t::value
&& !std::is_same::value,
MakeUnsignedT,
IdentityT
>::Type;
};

19.7.2 Detecting Nonthrowing Operations

It is occasionally useful to determine whether a particular operation can throw an
exception. For example, a move constructor should be marked noexcept,
indicating that it does not throw exceptions, whenever possible. However,
whether a move constructor for a particular class throws exceptions or not often
depends on whether the move constructors of its members and bases throw. For
example, consider the move constructor for a simple class template Pair: Click
here to view code image
template
class Pair {
T1 first;
T2 second;
public:
Pair(Pair&& other)
: first(std::forward(other.first)),
second(std::forward(other.second)) {
}
};

Pair’s move constructor can throw exceptions when the move operations of
either T1 or T2 can throw. Given a trait
IsNothrowMoveConstructibleT, we can express this property by using a
computed noexcept exception specification in Pair’s move constructor. For
example: Click here to view code image
Pair(Pair&& other) noexcept(IsNothrowMoveConstructibleT::value &&
IsNothrowMoveConstructibleT::value)
: first(std::forward(other.first)),
second(std::forward(other.second))
{
}

All that remains is to implement the IsNothrowMoveConstructibleT
trait. We can directly implement this trait using the noexcept operator, which
determines whether a given expression is guaranteed to be nonthrowing: Click
here to view code image
traits/isnothrowmoveconstructible1.hpp
#include  // for declval
#include  // for bool_constant
template
struct IsNothrowMoveConstructibleT
: std::bool_constant()))>
{
};

Here, the operator version of noexcept is used, which determines whether an
expression is non-throwing. Because the result is a Boolean value, we can pass it
directly to define the base class, std::bool_constant<>, which is used to
define std::true_type and std::false_type (see Section 19.3.3 on
page 411).24
However, this implementation should be improved because it is not SFINAEfriendly (see Section 19.4.4 on page 424): If the trait is instantiated with a type
that does not have a usable move or copy constructor—making the expression
T(std::declval()) invalid—the entire program is ill-formed:
Click here to view code image
class E {
public:
E(E&&) = delete;
};
…
std::cout << IsNothrowMoveConstructibleT::value; // compile-time
ERROR

Instead of aborting the compilation, the type trait should yield a value of
false.
As discussed in Section 19.4.4 on page 424, we have to check whether the
expression computing the result is valid before it is evaluated. Here, we have to
find out whether move construction is valid before checking whether it is
noexcept. Thus, we revise the first version of the trait by adding a template
parameter that defaults to void and a partial that uses std::void_t for that
parameter with an argument that is valid only if move construction is valid:
Click here to view code image
traits/isnothrowmoveconstructible2.hpp
#include  // for declval
#include  // for true_type, false_type, and
bool_constant<>
// primary template:
template>
struct IsNothrowMoveConstructibleT : std::false_type
{
};
// partial specialization (may be SFINAE’d away):
template
struct IsNothrowMoveConstructibleT
()))>>

: std::bool_constant()))>
{
};

If the substitution of std::void_t<…> in the partial specialization is valid,
that specialization is selected, and the noexcept(…) expression in the base
class specifier can safely be evaluated. Otherwise, the partial specialization is
discarded without instantiating it, and the primary template is instantiated
instead (producing a std::false_type result.
Note that there is no way to check whether a move constructor throws without
being able to call it directly. That is, it is not enough that the move constructor is
public and not deleted, it also requires that the corresponding type is no abstract
class (references or pointers to abstract classes work fine). For this reason, the
type trait is named IsNothrowMoveConstructible instead of HasNothrowMoveConstructor. For anything else, we’d need compiler support.
The C++ standard library provides a corresponding type trait
std::is_move_constructible<>, which is described in Section D.3.2
on page 721.

19.7.3 Traits Convenience
One common complaint with type traits is their relative verbosity, because each
use of a type trait typically requires a trailing ::Type and, in a dependent
context, a leading typename keyword, both of which are boilerplate. When
multiple type traits are composed, this can force some awkward formatting, as in
our running example of the array operator+, if we would implement it
correctly, ensuring that no constant or reference type is returned: Click here to
view code image
template
Array<
typename RemoveCVT<
typename RemoveReferenceT<
typename PlusResultT::Type
>::Type
>::Type
>
operator+ (Array const&, Array const&); By using alias
templates and variable templates, we can make the usage of the
traits, yielding types or values respectively more convenient.
However, note that in some contexts these shortcuts are not usable,
and we have to use the original class template instead. We already

discussed one such situation in our MemberPointerToIntT example, but
a more general discussion follows.

Alias Templates and Traits
As introduced in Section 2.8 on page 39, alias templates offer a way to reduce
verbosity. Rather than expressing a type trait as a class template with a type
member Type, we can use an alias template directly. For example, the following
three alias templates wrap the type traits used above: Click here to view code
image
template
using RemoveCV = typename RemoveCVT::Type;
template
using RemoveReference = typename RemoveReferenceT::Type;
template
using PlusResult = typename PlusResultT::Type; Given these
alias templates, we can simplify our operator+ declaration down to
Click here to view code image
template
Array>>>
operator+ (Array const&, Array const&); This second version
is clearly shorter and makes the composition of the traits more
obvious. Such improvements make alias templates more suitable for
some uses of type traits.

However, there are downsides to using alias templates for type traits: 1. Alias
templates cannot be specialized (as noted in Section 16.3 on page 338), and
since many of the techniques for writing traits depend on specialization, an alias
template will likely need to redirect to a class template anyway.
2. Some traits are meant to be specialized by users, such as a trait that describes
whether a particular addition operation is commutative, and it can be
confusing to specialize the class template when most uses involve the alias
template.
3. The use of an alias template will always instantiate the type (e.g., the
underlying class template specialization), which makes it harder to avoid
instantiating traits that don’t make sense for a given type (as discussed in
Section 19.7.1 on page 440).
Another way to express this last point, is that alias templates cannot be used with
metafunction forwarding (see Section 19.3.2 on page 404).
Because the use of alias templates for type traits has both positive and
negative aspects, we recommend using them as we have in this section and as it

is done in the C++ standard library: Provide both class templates with a specific
naming convention (we have chosen the T suffix and the Type type member)
and alias templates with a slightly different naming convention (we dropped the
T suffix), and have each alias template defined in terms of the underlying class
template. This way, we can use alias templates wherever they provide clearer
code, but fall back to class templates for more advanced uses.
Note that for historical reasons, the C++ standard library has a different
convention. The type traits class templates yield a type in type and have no
specific suffix (many were introduced in C++11). Corresponding alias templates
(that produce the type directly) started being introduced in C++14, and were
given a _t suffix, since the unsuffixed name was already standardized (see
Section D.1 on page 697).
Variable Templates and Traits
Traits returning a value require a trailing ::value (or similar member
selection) to produce the result of the trait. In this case, constexpr variable
templates (introduced in Section 5.6 on page 80) offer a way to reduce this
verbosity.
For example, the following variable templates wrap the IsSameT trait
defined in Section 19.3.3 on page 410 and the IsConvertibleT trait defined
in Section 19.5 on page 428: Click here to view code image
template
constexpr bool IsSame = IsSameT::value;
template
constexpr bool IsConvertible = IsConvertibleT::value; Now
we can simply write
Click here to view code image
if (IsSame || IsConvertible) …

instead of
Click here to view code image
if (IsSameT::value || IsConvertibleT::value) …

Again, for historical reasons, the C++ standard library has a different
convention. The traits class templates producing a result in value have no
specific suffix, and many of them were introduced in the C++11 standard. The
corresponding variable templates that directly produce the resulting value were
introduced in C++17 with a _v suffix (see Section D.1 on page 697).25

19.8 Type Classification
It is sometimes useful to be able to know whether a template parameter is a
built-in type, a pointer type, a class type, and so on. In the following sections, we
develop a suite of type traits that allow us to determine various properties of a
given type. As a result, we will be able to write code specific for some types:
Click here to view code image
if (IsClassT::value) {
…
}

or, using the compile-time if available since C++17 (see Section 8.5 on page
134) and the features for traits convenience (see Section 19.7.3 on page 446):
Click here to view code image
if constexpr (IsClass) {
…
}

or, by using partial specializations:
Click here to view code image
template>
class C { //primary template for the general case
…
};
template
class C { //partial specialization for class types
…
};

Furthermore, expressions such as IsPointerT::value will be Boolean
constants that are valid nontype template arguments. In turn, this allows the
construction of more sophisticated and more powerful templates that specialize
their behavior on the properties of their type arguments.
The C++ standard library defines several similar traits to determine the
primary and composite type categories of a type.26 See Section D.2.1 on page
702 and Section D.2.2 on page 706 for details.

19.8.1 Determining Fundamental Types
To start, let’s develop a template to determine whether a type is a fundamental

type. By default, we assume a type is not fundamental, and we specialize the
template for the fundamental cases: Click here to view code image
traits/isfunda.hpp
#include  // for nullptr_t
#include  // for true_type, false_type, and
bool_constant<>
// primary template: in general T is not a fundamental type
template
struct IsFundaT : std::false_type {
};
// macro to specialize for fundamental types
#define MK_FUNDA_TYPE(T) \
template<> struct IsFundaT : std::true_type { \
};
MK_FUNDA_TYPE(void)
MK_FUNDA_TYPE(bool)
MK_FUNDA_TYPE(char)
MK_FUNDA_TYPE(signed char)
MK_FUNDA_TYPE(unsigned char)
MK_FUNDA_TYPE(wchar_t)
MK_FUNDA_TYPE(char16_t)
MK_FUNDA_TYPE(char32_t)
MK_FUNDA_TYPE(signed short)
MK_FUNDA_TYPE(unsigned short)
MK_FUNDA_TYPE(signed int)
MK_FUNDA_TYPE(unsigned int)
MK_FUNDA_TYPE(signed long)
MK_FUNDA_TYPE(unsigned long)
MK_FUNDA_TYPE(signed long long)
MK_FUNDA_TYPE(unsigned long long)
MK_FUNDA_TYPE(float)
MK_FUNDA_TYPE(double)
MK_FUNDA_TYPE(long double)
MK_FUNDA_TYPE(std::nullptr_t)
#undef MK_FUNDA_TYPE

The primary template defines the general case. That is, in general,
IsFundaT::value will evaluate to false: Click here to view code
image

template
struct IsFundaT : std::false_type {
static constexpr bool value = false;
};

For each fundamental type, a specialization is defined so that
IsFundaT::value is true. We define a macro that expands to the
necessary code for convenience. For example: Click here to view code image
MK_FUNDA_TYPE(bool)

expands to the following:
Click here to view code image
template<> struct IsFundaT : std::true_type {
static constexpr bool value = true;
};

The following program demonstrates a possible use of this template: Click here
to view code image
traits/isfundatest.cpp
#include "isfunda.hpp"
#include 
template
void test (T const&)
{
if (IsFundaT::value) {
std::cout << "T is a fundamental type" << ’\n’;
}
else {
std::cout << "T is not a fundamental type" << ’\n’;
}
}
int main()
{
test(7);
test("hello");
}

It has the following output:
Click here to view code image
T is a fundamental type
T is not a fundamental type

In the same way, we can define type functions IsIntegralT and

IsFloatingT to identify which of these types are integral scalar types and
which are floating-point scalar types.
The C++ standard library uses a more fine-grained approach than only to
check whether a type is a fundamental type. It first defines primary type
categories, where each type matches exactly one type category (see Section
D.2.1 on page 702), and then composite type categories such as
std::is_integral or std::is_fundamental (see Section D.2.2 on
page 706).

19.8.2 Determining Compound Types
Compound types are types constructed from other types. Simple compound
types include pointer types, lvalue and rvalue reference types, pointer-to-member
types, and array types. They are constructed from one or two underlying types.
Class types and function types are also compound types, but their composition
can involve an arbitrary number of types (for parameters or members).
Enumeration types are also considered nonsimple compound types in this
classification even though they are not compound from multiple underlying
types. Simple compound types can be classified using partial specialization.
Pointers
We start with one such simple classification, for pointer types: Click here to
view code image
traits/ispointer.hpp
template
struct IsPointerT : std::false_type { //primary template: by default
not a pointer
};
template
struct IsPointerT : std::true_type { //partial specialization for
pointers
using BaseT = T; // type pointing to
};

The primary template is a catch-all case for nonpointer types and, as usual,
provides its value constant false through is base class

std::false_type, indicating that the type is not a pointer. The partial
specialization catches any kind of pointer (T*) and provides the value true
to indicate that the provided type is a pointer. Additionally, it provides a type
member BaseT that describes the type that the pointer points to. Note that this
type member is only available when the original type was a pointer, making this
a SFINAE-friendly type trait (see Section 19.4.4 on page 424).
The C++ standard library provides a corresponding trait
std::is_pointer<>, which, however, does not provide a member for the
type the pointer points to. It is described in Section D.2.1 on page 704.
References
Similarly, we can identify lvalue reference types:
Click here to view code image

traits/islvaluereference.hpp
template
struct IsLValueReferenceT : std::false_type { //by default no lvalue
reference
};
template
struct IsLValueReferenceT : std::true_type { //unless T is lvalue
references
using BaseT = T; // type referring to
};

and rvalue reference types:
Click here to view code image

traits/isrvaluereference.hpp
template
struct IsRValueReferenceT : std::false_type { //by default no rvalue
reference
};
template
struct IsRValueReferenceT : std::true_type { //unless T is rvalue
reference
using BaseT = T; // type referring to
};

which can be combined into an IsReferenceT<> trait: Click here to view

code image
traits/isreference.hpp
#include "islvaluereference.hpp"
#include "isrvaluereference.hpp"
#include "ifthenelse.hpp"
template
class IsReferenceT
: public IfThenElseT::value,
IsLValueReferenceT,
IsRValueReferenceT
>::Type {
};

In this implementation, we use IfThenElseT (from Section 19.7.1 on page
440) to select between either IsLValueReference or
IsRValueReference as our base class, using metafunction forwarding
(discussed in Section 19.3.2 on page 404). If T is an lvalue reference, we inherit
from IsLValueReference to get the appropriate value and BaseT
members. Otherwise, we inherit from IsRValueReference, which
determines whether the type is an rvalue reference or not (and provides the
appropriate member(s) in either case).
The C++ standard library provides the corresponding traits
std::is_lvalue_reference<> and
std::is_rvalue_reference<>, which are described in Section D.2.1 on
page 705, and std::is_reference<>, which is described in Section D.2.2
on page 706. Again, these traits do not provide a member for the type the
reference refers to.
Arrays
When defining traits to determine arrays, it may come as a surprise that the
partial specializations involve more template parameters than the primary
template: Click here to view code image
traits/isarray.hpp
#include 
template
struct IsArrayT : std::false_type { //primary template: not an array

};
template
struct IsArrayT : std::true_type { //partial specialization for
arrays
using BaseT = T;
static constexpr std::size_t size = N;
};
template
struct IsArrayT : std::true_type { //partial specialization for
unbound arrays
using BaseT = T;
static constexpr std::size_t size = 0;
};

Here, multiple additional members provide information about the arrays being
classified: their base type and their size (with 0 used to denote an unknown size).
The C++ standard library provides the corresponding trait
std::is_array<> to check whether a type is an array, which is described in
Section D.2.1 on page 704. In addition, traits such as std::rank<> and
std::extent<> allow us to query their number of dimensions and the size of
a specific dimension (see Section D.3.1 on page 715).
Pointers to Members
Pointers to members can be treated using the same technique: Click here to view
code image
traits/ispointertomember.hpp
template
struct IsPointerToMemberT : std::false_type { //by default no pointerto-member
};
template
struct IsPointerToMemberT : std::true_type { //partial
specialization
using MemberT = T;
using ClassT = C;
};

Here, the additional members provide both the type of the member and the type
of the class in which that member occurs.
The C++ standard library provides more specific traits,

std::is_member_object_pointer<> and
std::is_member_function_pointer<>, which are described in
Section D.2.1 on page 705, as well as std::is_member_pointer<>,
which is described in Section D.2.2 on page 706.

19.8.3 Identifying Function Types
Function types are interesting because they have an arbitrary number of
parameters in addition to the result type. Therefore, within the partial
specialization matching a function type, we employ a parameter pack to capture
all of the parameter types, as we did for the DecayT trait in Section 19.3.2 on
page 404: Click here to view code image
traits/isfunction.hpp
#include "../typelist/typelist.hpp"
template
struct IsFunctionT : std::false_type { //primary template: no function
};
template
struct IsFunctionT : std::true_type { //functions
using Type = R;
using ParamsT = Typelist;
static constexpr bool variadic = false;
};
template
struct IsFunctionT : std::true_type { //variadic
functions
using Type = R;
using ParamsT = Typelist;
static constexpr bool variadic = true;
};

Note that each part of the function type is exposed: Type provides the result type,
while all of the parameters are captured in a single typelist as ParamsT (typelists
are covered in Chapter 24), and variadic indicates whether the function type uses
C-style varargs.
Unfortunately, this formulation of IsFunctionT does not handle all
function types, because function types can have const and volatile
qualifiers as well as lvalue (&) and rvalue (&&) reference qualifiers (described in

Section C.2.1 on page 684) and, since C++17, noexcept qualifiers. For
example: Click here to view code image
using MyFuncType = void (int&) const; Such function types can only be
meaningfully used for nonstatic member functions but are function
types nonetheless. Moreover, a function type marked const is not
actually a const type,27 so RemoveConst is not able to strip the
const from the function type. Therefore, to recognize function types
that have qualifiers, we need to introduce a large number of
additional partial specializations, covering every combination of
qualifiers (both with and without C-style varargs). Here, we
illustrate only five of the many28 required partial specializations:
Click here to view code image
template
struct IsFunctionT : std::true_type {
using Type = R;
using ParamsT = Typelist;
static constexpr bool variadic = false;
};
template
struct IsFunctionT : std::true_type {
using Type = R;
using ParamsT = Typelist;
static constexpr bool variadic = true;
};
template
struct IsFunctionT : std::true_type {
using Type = R;
using ParamsT = Typelist;
static constexpr bool variadic = true;
};
template
struct IsFunctionT : std::true_type {
using Type = R;
using ParamsT = Typelist;
static constexpr bool variadic = true;
};
template
struct IsFunctionT : std::true_type {
using Type = R;
using ParamsT = Typelist;
static constexpr bool variadic = true;
};
…

With all this in place, we can now classify all types except class types and

enumeration types. We tackle these cases in the following sections.
The C++ standard library provides the trait std::is_function<>, which
is described in Section D.2.1 on page 706.

19.8.4 Determining Class Types
Unlike the other compound types we have handled so far, we have no partial
specialization patterns that match class types specifically. Nor is it feasible to
enumerate all class types, as it is for fundamental types. Instead, we need to use
an indirect method to identify class types, by coming up with some kind of type
or expression that is valid for all class types (and not other type). With that type
or expression, we can apply the SFINAE trait techniques discussed in Section
19.4 on page 416.
The most convenient property of class types to utilize in this case is that only
class types can be used as the basis of pointer-to-member types. That is, in a type
construct of the form X Y::*, Y can only be a class type. The following
formulation of IsClassT<> exploits this property (and picks int arbitrarily
for type X): Click here to view code image
traits/isclass.hpp
#include 
template>
struct IsClassT : std::false_type { //primary template: by default no
class
};
template
struct IsClassT> // classes can have pointerto-member
: std::true_type {
};

The C++ language specifies that the type of a lambda expression is a “unique,
unnamed non-union class type.” For this reason, lambda expressions yield true
when examining whether they are class type objects: Click here to view code
image
auto l = []{};
static_assert::value, "">; //succeeds

Note also that the expression int T::* is also valid for union types (they are
also class types according to the C++ standard).
The C++ standard library provides the traits std::is_class<> and
std::is_union<>, which are described in Section D.2.1 on page 705.
However, these traits require special compiler support because distinguishing
class and struct types from union types cannot currently be done using
any standard core language techniques.29

19.8.5 Determining Enumeration Types
The only types not yet classified by any of our traits are enumeration types.
Testing for enumeration types can be performed directly by writing a SFINAEbased trait that checks for an explicit conversion to an integral type (say, int)
and explicitly excluding fundamental types, class types, reference types, pointer
types, and pointer-to-member types, all of which can be converted to an integral
type but are not enumeration types.30 Instead, we simply note that any type that
does not fall into any of the other categories must be an enumeration type, which
we can implement as follows: Click here to view code image
traits/isenum.hpp
template
struct IsEnumT {
static constexpr bool value = !IsFundaT::value &&
!IsPointerT::value &&
!IsReferenceT::value &&
!IsArrayT::value &&
!IsPointerToMemberT::value &&
!IsFunctionT::value &&
!IsClassT::value;
};

The C++ standard library provides the trait std::is_enum<>, which is
described in Section D.2.1 on page 705. Usually, to improve compilation
performance, compilers will directly provide support for such a trait instead of
implementing it as “anything else.”

19.9 Policy Traits

So far, our examples of traits templates have been used to determine properties
of template parameters: what sort of type they represent, the result type of an
operator applied to values of that type, and so forth. Such traits are called
property traits.
In contrast, some traits define how some types should be treated. We call them
policy traits. This is reminiscent of the previously discussed concept of policy
classes (and we already pointed out that the distinction between traits and
policies is not entirely clear), but policy traits tend to be unique properties
associated with a template parameter (whereas policy classes are usually
independent of other template parameters).
Although property traits can often be implemented as type functions, policy
traits usually encapsulate the policy in member functions. To illustrate this
notion, let’s look at a type function that defines a policy for passing read-only
parameters.

19.9.1 Read-Only Parameter Types
In C and C++, function call arguments are passed by value by default. This
means that the values of the arguments computed by the caller are copied to
locations controlled by the callee. Most programmers know that this can be
costly for large structures and that for such structures it is appropriate to pass the
arguments by reference-to-const (or by pointer-to-const in C). For smaller
structures, the picture is not always clear, and the best mechanism from a
performance point of view depends on the exact architecture for which the code
is being written. This is not so critical in most cases, but sometimes even the
small structures must be handled with care.
With templates, of course, things get a little more delicate: We don’t know a
priori how large the type substituted for the template parameter will be.
Furthermore, the decision doesn’t depend just on size: A small structure may
come with an expensive copy constructor that would still justify passing readonly parameters by reference-to-const.
As hinted at earlier, this problem is conveniently handled using a policy traits
template that is a type function: The function maps an intended argument type T
onto the optimal parameter type T or T const&. As a first approximation, the
primary template can use by-value passing for types no larger than two pointers
and by reference-to-const for everything else: Click here to view code image
template

struct RParam {
using Type = typename IfThenElseT::Type;
};

On the other hand, container types for which sizeof returns a small value may
involve expensive copy constructors, so we may need many specializations and
partial specializations, such as the following: Click here to view code image
template
struct RParam> {
using Type = Array const&;
};

Because such types are common in C++, it may be safer to mark only small
types with trivial copy and move constructors as by value types31 and then
selectively add other class types when performance considerations dictate it (the
std::is_trivially_copy_constructible and
std::is_trivially_move_constructible type traits are part of the
C++ standard library).
Click here to view code image

traits/rparam.hpp
#ifndef RPARAM_HPP
#define RPARAM_HPP
#include "ifthenelse.hpp"
#include 
template
struct RParam {
using Type
= IfThenElse<(sizeof(T) <= 2*sizeof(void*)
&& std::is_trivially_copy_constructible::value
&& std::is_trivially_move_constructible::value),
T,
T const&>;
};
#endif //RPARAM_HPP

Either way, the policy can now be centralized in the traits template definition,
and clients can exploit it to good effect. For example, let’s suppose we have two
classes, with one class specifying that calling by value is better for read-only
arguments: Click here to view code image

traits/rparamcls.hpp
#include "rparam.hpp"
#include 
class MyClass1 {
public:
MyClass1 () {
}
MyClass1 (MyClass1 const&) {
std::cout << "MyClass1 copy constructor called\n";
}
};
class MyClass2 {
public:
MyClass2 () {
}
MyClass2 (MyClass2 const&) {
std::cout << "MyClass2 copy constructor called\n";
}
};
// pass MyClass2 objects with RParam<> by value
template<>
class RParam {
public:
using Type = MyClass2;
};

Now, we can declare functions that use RParam<> for read-only arguments and
call these functions: Click here to view code image
traits/rparam1.cpp
#include "rparam.hpp"
#include "rparamcls.hpp"
// function that allows parameter passing by value or by reference
template
void foo (typename RParam::Type p1,
typename RParam::Type p2)
{
…
}
int main()
{
MyClass1 mc1;
MyClass2 mc2;
foo(mc1,mc2);

}

Unfortunately, there are some significant downsides to using RParam. First, the
function declaration is significantly messier. Second, and perhaps more
objectionable, is the fact that a function like foo() cannot be called with
argument deduction because the template parameter appears only in the
qualifiers of the function parameters. Call sites must therefore specify explicit
template arguments.
An unwieldy workaround for this option is the use of an inline wrapper
function template that provides perfect forwarding (Section 15.6.3 on page 280),
but it assumes the inline function will be elided by the compiler. For example:
Click here to view code image
traits/rparam2.cpp
#include "rparam.hpp"
#include "rparamcls.hpp"
// function that allows parameter passing by value or by reference
template
void foo_core (typename RParam::Type p1,
typename RParam::Type p2)
{
…
}
// wrapper to avoid explicit template parameter passing
template
void foo (T1 && p1, T2 && p2)
{
foo_core(std::forward(p1),std::forward(p2));
}
int main()
{
MyClass1 mc1;
MyClass2 mc2;
foo(mc1,mc2); // same as foo_core(mc1,mc2)
}

19.10 In the Standard Library
With C++11, type traits became an intrinsic part of the C++ standard library.
They comprise more or less all type functions and type traits discussed in this

chapter. However, for some of them, such as the trivial operation detection traits
and as discussed std::is_union, there are no known in-language solutions.
Rather, the compiler provides intrinsic support for those traits. Also, compilers
start to support traits even if there are in-language solutions to shorten compile
time.
For this reason, if you need type traits, we recommend that you use the ones
from the C++ standard library whenever available. They are all described in
detail in Appendix D.
Note that (as discussed) some traits have potentially surprising behavior (at least
for the naive programmer). In addition to the general hints we give in Section
11.2.1 on page 164 and Section D.1.2 on page 700, also consider the specific
descriptions we provide in Appendix D.
The C++ standard library also defines some policy and property traits: • The
class template std::char_traits is used as a policy traits parameter by the
string and I/O stream classes.
• To adapt algorithms easily to the kind of standard iterators for which they are
used, a very simple std::iterator_traits property traits template is
provided (and used in standard library interfaces).
• The template std::numeric_limits can also be useful as a property
traits template.
• Lastly, memory allocation for the standard container types is handled using
policy traits classes. Since C++98, the template std::allocator is
provided as the standard component for this purpose. With C++11, the
template std::allocator_traits was added to be able to change the
policy/behavior of allocators (switching between the classical behavior and
scoped allocators; the latter could not be accommodated within the pre-C++11
framework).

19.11 Afternotes
Nathan Myers was the first to formalize the idea of traits parameters. He
originally presented them to the C++ standardization committee as a vehicle to
define how character types should be treated in standard library components
(e.g., input and output streams). At that time, he called them baggage templates
and noted that they contained traits. However, some C++ committee members
did not like the term baggage, and the name traits was promoted instead. The
latter term has been widely used since then.

Client code usually does not deal with traits at all: The default traits classes
satisfy the most common needs, and because they are default template
arguments, they need not appear in the client source at all. This argues in favor
of long descriptive names for the default traits templates. When client code does
adapt the behavior of a template by providing a custom traits argument, it is
good practice to declare a type alias name for the resulting specializations that is
appropriate for the custom behavior. In this case the traits class can be given a
long descriptive name without sacrificing too much source estate.
Traits can be used as a form of reflection, in which a program inspects its own
high-level properties (such as its type structures). Traits such as IsClassT and
PlusResultT, as well as many other type traits that inspect the types in the
program, implement a form of compile-time reflection, which turns out to be a
powerful ally to metaprogramming (see Chapter 23 and Section 17.9 on page
363).
The idea of storing properties of types as members of template specializations
dates back to at least the mid-1990s. Among the earlier serious applications of
type classification templates was the __type_traits utility in the STL
implementation distributed by SGI (then known as Silicon Graphics). The SGI
template was meant to represent some properties of its template argument (e.g.,
whether it was a plain old datatype (POD) or whether its destructor was trivial).
This information was then used to optimize certain STL algorithms for the given
type. An interesting feature of the SGI solution was that some SGI compilers
recognized the __type_traits specializations and provided information
about the arguments that could not be derived using standard techniques. (The
generic implementation of the __type_traits template was safe to use,
albeit suboptimal.) Boost provides a rather complete set of type classification
templates (see [BoostTypeTraits]) that formed the basis of the
 header in the 2011 C++ standard library. While many of
these traits can be implemented with the techniques described in this chapter,
others (such as std::is_pod, for detecting PODs) require compiler support,
much like the __type_traits specializations provided by the SGI compilers.
The use of the SFINAE principle for type classification purposes had been
noted when the type deduction and substitution rules were clarified during the
first standardization effort. However, it was never formally documented, and as a
result, much effort was later spent trying to re-create some of the techniques
described in this chapter. The first edition of this book was one of the earliest
sources for this technique, and it introduced the term SFINAE. One of the other
notable early contributors in this area was Andrei Alexandrescu, who made

popular the use of the sizeof operator to determine the outcome of overload
resolution. This technique became popular enough that the 2011 standard
extended the reach of SFINAE from simple type errors to arbitrary errors within
the immediate context of the function template (see [SpicerSFINAE]). This
extension, in combination with the addition of decltype, rvalue references,
and variadic templates, greatly expanded the ability to test for specific properties
within traits.
Using generic lambdas like isValid to extract the essence of a SFINAE
condition is a technique introduced by Louis Dionne in 2015, which is used by
Boost.Hana (see [BoostHana]), a metaprogramming library suited for compiletime computations on both types and values.
Policy classes have apparently been developed by many programmers and a
few authors. Andrei Alexandrescu made the term policy classes popular, and his
book Modern C++ Design covers them in more detail than our brief section (see
[AlexandrescuDesign]).
1 Most examples in this section use ordinary pointers for the sake of simplicity.
Clearly, an industrial-strength interface may prefer to use iterator parameters
following the conventions of the C++ standard library (see [JosuttisStdLib]).
We revisit this aspect of our example later.
2 EBCDIC is an abbreviation of Extended Binary-Coded Decimal Interchange
Code, which is an IBM character set that is widely used on large IBM
computers.
3 In C++11, you have to declare the return type like type AccT.
4 Most modern C++ compilers can “see through” calls of simple inline
functions. Additionally, the use of constexpr makes it possible to use the
value traits in contexts where the expression must be a constant (e.g., in a
template argument).
5 We could generalize this to a policy parameter, which could be a class (as
discussed) or a pointer to a function.
6 Alexandrescu has been the main voice in the world of policy classes, and he
has developed a rich set of techniques based on them.
7 In C++11, you have to declare the return type as VT.
8 The order in which the qualifiers is removed has no semantic consequence:
We could first remove volatile and then const instead.
9 Using the term decay might be slightly confusing because in C it only implies
the conversion from array/-function types to to pointer types, whereas here it
also includes the removal of top-level const/volatile qualifiers.

10

Strictly speaking, the comma prior to the second ellipsis (…) is optional but is
provided here for clarity. Due to the ellipsis being optional, the function type
in the first partial specialization is actually syntactically ambiguous: It can be
parsed as either R(Args, …) (a C-style varargs parameter) or R(Args…
name) (a parameter pack). The second interpretation is picked because Args
is an unexpanded parameter pack. We can explicitly add the comma in the
(rare) cases where the other interpretation is desired.
11 The difference between the return types T and T&& is discoverable by direct
use of decltype. However, given declval’s limited use, this is not of
practical interest.
12 The fallback declaration can sometimes be a plain member function
declaration instead of a member function template.
13 However, the SFINAE rules were more limited back then: When substitution
of template arguments resulted in a malformed type construct (e.g., T::X
where T is int), SFINAE worked as expected, but if it resulted in an invalid
expression (e.g., sizeof(f()) where f() returns void), SFINAE did not
kick in and an error was issued right away.
14 The first edition of this book was perhaps the first source for this technique.
15 Defining void_t inside namespace std is formally invalid: User code is not
permitted to add declarations to namespace std. In practice, no current
compiler enforces that restriction, nor do they behave unexpectedly (the
standard indicates that doing this leads to “undefined behavior,” which allows
anything to happen).
16 At the time of this writing, Microsoft Visual C++ is the unfortunate exception.
17 Thanks to Louis Dionne for pointing out the technique described in this
section.
18 This very simple pair of helper templates is a fundamental technique that lies
at the heart of advanced libraries such as Boost.Hana!
19 This code is not valid C++ because a lambda expression cannot appear directly
in a decltype operand for compiler-technical reasons, but the meaning is
clear.
20 For simplicity, the return value just uses PlusResultT::Type.
In practice, the return type should also be computed using
RemoveReferenceT<> and RemoveCVT<> to avoid that references are
returned.
21 At the time of this writing, the C++ standardization committee is exploring

ways to “reflect” various program entities (like class types and their members)
in ways that the program can explore. See Section 17.9 on page 363.
22 Except that decltype(call-expression) does not require a nonreference,
non-void return type to be complete, unlike call expressions in other
contexts. Using decltype(std::declval().begin(), 0)
instead does add the requirement that the return type of the call is complete,
because the returned value is no longer the result of the decltype operand.
23 Prior to C++11’s expansion of SFINAE to cover arbitrary invalid expressions,
the techniques for detecting the validity of specific expressions centered on
introducing a new overload for the function being tested (e.g., <) that had an
overly permissive signature and a strangely sized return type to behave as a
fallback case. However, such approaches were prone to ambiguities and
caused errors due to access control violations.
24 In C++11 and C++14, we have to specify the base class as
std::integral_constant instead of
std::bool_constant<…>.
25 The C++ standardization committee is further bound by a long-standing
tradition that all standard names consist of lowercase characters and optional
underscores to separate them. That is, a name like isSame or IsSame is
unlikely to ever be seriously considered for standardization (except for
concepts, where this spelling style will be used).
26 The use of “primary” vs. “composite” type categories should not be confused
with the distinction between “fundamental” vs. “compound” types. The
standard describes fundamental types (like int or std::nullptr_t) and
compound types (like pointer types and class types). This is different from
composite type categories (like arithmetic), which are categories that are the
union of primary type categories (like floating-point).
27 Specifically, when a function type is marked const, it refers to a qualifier on
the object pointed to by the implicit parameter this, whereas the const on a
const type refers to the object of that actual type.
28 The latest count is 48.
29 Most compilers support intrinsic operators like __is_union to help standard
libraries implement various traits templates. This is true even for some traits
that could technically be implemented using the techniques from this chapter,
because the intrinsics can improve compilation performance.
30 The first edition of this book described enumeration type detection in this way.
However, it checked for an implicit conversion to an integral type, which

sufficed for the C++98 standard. The introduction of scoped enumeration types
into the language, which do not have such an implicit conversion, complicates
the detection of enumeration types.
31 A copy or move constructor is called trivial if, in effect, a call to it can be
replaced by a simple copy of the underlying bytes.

Chapter 20
Overloading on Type Properties
Function overloading allows the same function name to be used for multiple
functions, so long as those functions are distinguished by their parameter types.
For example: void f (int);
void f (char const*); With function templates, one overloads on type patterns
such as pointer-to-T or Array: Click here to view code image
template void f(T*);
template void f(Array); Given the prevalence of type
traits (discussed in Chapter 19), it is natural to want to overload
function templates based on the properties of the template arguments.
For example: Click here to view code image
template void f(Number); // only for numbers
template void f(Container);// only for containers

However, C++ does not currently provide any direct way to express overloads
based on type properties. In fact, the two f function templates immediately
above are actually declarations of the same function template, rather than distinct
overloads, because the names of template parameters are ignored when
comparing two function templates.
Fortunately, there are a number of techniques that can be used to emulate
overloading of function templates based on type properties. These techniques, as
well as the common motivations for such overloading, are discussed in this
chapter.

20.1 Algorithm Specialization
One of the common motivations behind overloading of function templates is to
provide more specialized versions of an algorithm based on knowledge of the
types involved. Consider a simple swap() operation to exchange two values:
Click here to view code image
template
void swap(T& x, T& y)

{
T tmp(x);
x = y;
y = tmp;
}

This implementation involves three copy operations. For some types,
however, we can provide a more efficient swap() operation, such as for an
Array that stores its data as a pointer to the array contents and a length:
Click here to view code image
template
void swap(Array& x, Array& y)
{
swap(x.ptr, y.ptr);
swap(x.len, y.len);
}

Both implementations of swap() will correctly exchange the contents of two
Array objects. However, the latter implementation is more efficient,
because it makes use of additional properties of an Array (specifically,
knowledge of ptr and len and their respective roles) that are not available for
an arbitrary type.1 The latter function template is therefore (conceptually) more
specialized than the former, because it performs the same operation for a subset
of the types accepted by the former function template. Fortunately, the second
function template is also more specialized based on the partial ordering rules for
function templates (see Section 16.2.2 on page 330), so the compiler will pick
the more specialized (and, therefore, more efficient) function template when it is
applicable (i.e., for Array arguments) and fall back to the more general
(potentially less efficient) algorithm when the more specialized version is not
applicable.
The design and optimization approach of introducing more specialized
variants of a generic algorithm is called algorithm specialization. The more
specialized variants apply to a subset of the valid inputs for the generic
algorithm, identifying this subset based on the specific types or properties of the
types, and are typically more efficient than the most general implementation of
that generic algorithm.
Crucial to the implementation of algorithm specialization is the property that
the more specialized variants are automatically selected when they are
applicable, without the caller having to be aware that those variants even exist.
In our swap() example, this was accomplished by overloading the
(conceptually) more specialized function template (the second swap()) with

the most general function template (the first swap()), and ensuring that the
more specialized function template was also more specialized based on C++’s
partial ordering rules.
Not all conceptually more specialized algorithm variants can be directly
translated into function templates that provide the right partial ordering behavior.
For our next example, consider However, the alternative presented here is more
broadly applicable.
the advanceIter() function (similar to std::advance() from the
C++ standard library), which moves an iterator x forward by n steps. This
general algorithm can operate on any input iterator: Click here to view code
image
template
void advanceIter(InputIterator& x, Distance n)
{
while (n > 0) { //linear time
++x;
--n;
}
}

For a certain class of iterators—those that provide random access operations—
we can provide a more efficient implementation: Click here to view code image
template
void advanceIter(RandomAccessIterator& x, Distance n) {
x += n; // constant time
}

Unfortunately, defining both of these function templates will result in a compiler
error, because— as noted in the introduction—function templates that differ only
based on their template parameter names are not overloadable. The remainder of
this chapter will discuss techniques that emulate the desired effect of overloading
these function templates.

20.2 Tag Dispatching
One approach to algorithm specialization is to “tag” different implementation
variants of an algorithm with a unique type that identifies that variant. For
example, to deal with the advanceIter() problem, just introduced, we can
use the standard library’s iterator category tag types (defined below) to identify
the two implementation variants of the advanceIter() algorithm: Click here

to view code image
template
void advanceIterImpl(Iterator& x, Distance n,
std::input_iterator_tag)
{
while (n > 0) { //linear time
++x;
--n;
}
}
template
void advanceIterImpl(Iterator& x, Distance n,
std::random_access_iterator_tag) {
x += n; // constant time
}

Then, the advanceIter() function template itself simply forwards its
arguments along with the appropriate tag: Click here to view code image
template
void advanceIter(Iterator& x, Distance n)
{
advanceIterImpl(x, n,
typename
std::iterator_traits::iterator_category());
}

The trait class std::iterator_traits provides a category for the
iterator via its member type iterator_category. The iterator category is
one of the _tag types mentioned earlier, which spec-ifies what kind of iterator
the type is. Inside the C++ standard library, the available tags are defined as
follows, using inheritance to reflect when one tag describes a category that is
derived from another:2
Click here to view code image
namespace std {
struct input_iterator_tag { };
struct output_iterator_tag { };
struct forward_iterator_tag : public input_iterator_tag { };
struct bidirectional_iterator_tag : public forward_iterator_tag { };
struct random_access_iterator_tag : public bidirectional_iterator_tag
{ };
}

The key to effective use of tag dispatching is in the relationship among the tags.
Our two variants of advanceIterImpl() are tagged with
std::input_iterator_tag and with
std::random_access_iterator_tag, and because

std::random_access_iterator_tag inherits from
std::input_iterator_tag, normal function overloading will prefer the
more specialized algorithm variant (which uses
std::random_access_iterator_tag) whenever
advanceIterImpl() is called with a random access iterator. Therefore, tag
dispatching relies on delegation from the single, primary function template to a
set of _impl variants, which are tagged such that normal function overloading
will select the most specialized algorithm that is applicable to the given template
arguments.
Tag dispatching works well when there is a natural hierarchical structure to
the properties used by the algorithm and an existing set of traits that provide
those tag values. It is not as convenient when algorithm specialization depends
on ad hoc type properties, such as whether the type T has a trivial copy
assignment operator. For that, we need a more powerful technique.

20.3 Enabling/Disabling Function Templates
Algorithm specialization involves providing different function templates that are
selected on the basis of the properties of the template arguments. Unfortunately,
neither partial ordering of function templates (Section 16.2.2 on page 330) nor
overload resolution (Appendix C) is powerful enough to express more advanced
forms of algorithm specialization.
One helper the C++ standard library provides for this is std::enable_if,
which is introduced in Section 6.3 on page 98. This section discusses how this
helper can be implemented by introducing a corresponding alias template, which
we’ll call EnableIf to avoid name clashes.
Just like std::enable_if, the EnableIf alias template can be used to
enable (or disable) a specific function template under specific conditions. For
example, the random-access version of the advanceIter() algorithm can be
implemented as follows: Click here to view code image
template
constexpr bool IsRandomAccessIterator =
IsConvertible<
typename std::iterator_traits::iterator_category,
std::random_access_iterator_tag>;
template
EnableIf>
advanceIter(Iterator& x, Distance n){
x += n; // constant time

}

The EnableIf specialization here is used to enable this variant of
advanceIter() only when the iterator is in fact a random access iterator. The
two arguments to EnableIf are a Boolean condition indicating whether this
template should be enabled and the type produced by the EnableIf expansion
when the condition is true. In our example above, we used the type trait
IsConvertible, introduced in Section 19.5 on page 428 and Section 19.7.3
on page 447, as our condition, to define a type trait
IsRandomAccessIterator. Thus, this specific version of our
advanceIter() implementation is only considered if the concrete type
substituted for Iterator is usable as a random-access iterator (i.e., it is
associated with a tag convertible to
std::random_access_iterator_tag.
EnableIf has a fairly simple implementation: Click here to view code
image
typeoverload/enableif.hpp
template
struct EnableIfT {
};
template< typename T>
struct EnableIfT {
using Type = T;
};
template
using EnableIf = typename EnableIfT::Type; EnableIf expands
to a type and is therefore implemented as an alias template. We want
to use partial specialization (see Chapter 16) for its implementation,
but alias templates cannot be partially specialized. Fortunately, we
can introduce a helper class template EnableIfT, which does the actual
work we need, and have the alias template EnableIf simply select the
result type from the helper template. When the condition is true,
EnableIfT<…>::Type (and therefore EnableIf<…>) simply evaluates to the
second template argument, T. When the condition is false, EnableIf
does not produce a valid type, because the primary class template for
EnableIfT has no member named Type. Normally, this would be an error,
but in a SFINAE (substitution failure is not an error, described in
Section 15.7 on page 284) context—such as the return type of a
function template—it has the effect of causing template argument
deduction to fail, removing the function template from consideration.3

For advanceIter(), the use of EnableIf means that the function

template will be available (and have a return type of void) when the
Iterator argument is a random access iterator, and will be removed from
consideration when the Iterator argument is not a random access iterator. We
can think of EnableIf as a way to “guard” templates against instantiation with
template arguments that don’t meet the requirements of the template
implementation, because this advanceIter() can only be instantiated with a
random access iterator as it requires operations only available on a random
access iterator. While using EnableIf in this manner is not bulletproof—the
user could assert that a type is a random access iterator without providing the
necessary operations—it can help diagnose common mistakes earlier.
We now have established how to explicitly “activate” the more specialized
template for the types to which is applies. However, that is not sufficient: We
also have to “de-activate” the less specialized template, because a compiler has
no way to “order” the two and will report an ambiguity error if both versions
apply. Fortunately, achieving that is not hard: We just use the same EnableIf
pattern on the less specialized template, except that we negate the condition
expression. Doing so ensures that exactly one of the two templates will be
activated for any concrete Iterator type. Thus, our version of
advanceIter() for an iterator that is not a random access iterator becomes
the following: Click here to view code image
template
EnableIf>
advanceIter(Iterator& x, Distance n)
{
while (n > 0) {//linear time
++x;
--n;
}
}

20.3.1 Providing Multiple Specializations
The previous pattern generalizes to cases where more than two alternative
implementations are needed: We equip each alternative with EnableIf
constructs whose conditions are mutually exclusive for a specific set of concrete
template arguments. Those conditions will typically make use of various
properties that can be expressed via traits.
Consider, for example, the introduction of a third variant of the
advanceIter() algorithm: This time we want to permit moving “backward”

by specifying a negative distance.4 That is clearly invalid for an input iterator,
and clearly valid for a random access iterator. However, the standard library also
includes the notion of a bidirectional iterator, which allows backward movement
without requiring random access. Implementing this case requires slightly more
sophisticated logic: Each function template must use EnableIf with a
condition that is mutually exclusive with the conditions of all of the other
function templates that represent different variants of the algorithm. This results
in the following set of conditions: • Random access iterator: Random access case
(constant time, forward or backward) • Bidirectional iterator and not random
access: Bidirectional case (linear time, forward or backward) • Input iterator and
not bidirectional: General case (linear time, forward) The following set of
function templates implements this: Click here to view code image
typeoverload/advance2.hpp
#include 
// implementation for random access iterators:
template
EnableIf>
advanceIter(Iterator& x, Distance n) {
x += n; // constant time
}
template
constexpr bool IsBidirectionalIterator =
IsConvertible<
typename std::iterator_traits::iterator_category,
std::bidirectional_iterator_tag>;
// implementation for bidirectional iterators:
template
EnableIf &&
!IsRandomAccessIterator>
advanceIter(Iterator& x, Distance n) {
if (n > 0) {
for ( ; n > 0; ++x, --n) { //linear time
}
} else {
for ( ; n < 0; --x, ++n) { //linear time
}
}
}
// implementation for all other iterators:
template
EnableIf>
advanceIter(Iterator& x, Distance n) {

if (n < 0) {
throw "advanceIter(): invalid iterator category for negative n";
}
while (n > 0) { //linear time
++x;
--n;
}
}

By making the EnableIf condition of each function template mutually
exclusive with the EnableIf conditions of every other function template, we
ensure that, at most, one of the function templates will succeed template
argument deduction for a given set of arguments.
Our example illustrates one of the disadvantages of using EnableIf for
algorithm specialization: Each time a new variant of the algorithm is introduced,
the conditions of all of the algorithm variants need to be revisited to ensure that
all are mutually exclusive. In contrast, introducing the bidirectional-iterator
variant using tag dispatching (Section 20.2 on page 467) requires just the
addition of a new advanceIterImpl() overload using the tag
std::bidirectional_iterator_tag.
Both techniques—tag dispatching and EnableIf—are useful in different
contexts: Generally speaking, tag dispatching supports simple dispatching based
on hierarchical tags, while EnableIf supports more advanced dispatching
based on arbitrary sets of properties determined by type traits.

20.3.2 Where Does the EnableIf Go?
EnableIf is typically used in the return type of the function template.
However, this approach does not work for constructor templates or conversion
function templates, because neither has a specified return type.5 Moreover, the
use of EnableIf can make the return type very hard to read. In such cases, we
can instead embed the EnableIf in a defaulted template argument, as follows:
Click here to view code image
typeoverload/container1.hpp
#include 
#include "enableif.hpp"
#include "isconvertible.hpp"
template
constexpr bool IsInputIterator =

IsConvertible<
typename std::iterator_traits::iterator_category,
std::input_iterator_tag>;
template
class Container {
public:
// construct from an input iterator sequence:
template>>
Container(Iterator first, Iterator last);
// convert to a container so long as the value types are convertible:
template>>
operator Container() const;
};

However, there is a problem here. If we attempt to add yet another overload
(e.g., a more efficient version of the Container constructor for random access
iterators), it will result in an error: Click here to view code image
// construct from an input iterator sequence:
template &&
!IsRandomAccessIterator>>
Container(Iterator first, Iterator last);
template>>
Container(Iterator first, Iterator last); // ERROR: redeclaration
// of constructor template

The problem is that the two constructor templates are identical except for the
default template argument, but default template arguments are not considered
when determining whether two templates are equivalent.
We can alleviate this problem by adding yet another defaulted template
parameter, so the two constructor templates have a different number of template
parameters: Click here to view code image
// construct from an input iterator sequence:
template &&
!IsRandomAccessIterator>>
Container(Iterator first, Iterator last);
template>,
typename = int> // extra dummy parameter to enable both constructors
Container(Iterator first, Iterator last); //OK now

20.3.3 Compile-Time if
It’s worth noting here that C++17’s constexpr if feature (see Section 8.5 on page
134) avoids the need for EnableIf in many cases. For example, in C++17 we
can rewrite our advanceIter() example as follows: Click here to view code
image
typeoverload/advance3.hpp
template
void advanceIter(Iterator& x, Distance n) {
if constexpr(IsRandomAccessIterator) {
// implementation for random access iterators:
x += n; // constant time
}
else if constexpr(IsBidirectionalIterator) {
// implementation for bidirectional iterators:
if (n > 0) {
for ( ; n > 0; ++x, --n) { //linear time for positive n
}
} else {
for ( ; n < 0; --x, ++n) { //linear time for negative n
}
}
}
else {
// implementation for all other iterators that are at least input
iterators:
if (n < 0) {
throw "advanceIter(): invalid iterator category for negative n";
}
while (n > 0) { //linear time for positive n only
++x;
--n;
}
}
}

This is much clearer. The more-specialized code paths (e.g., for random access
iterators) will only be instantiated for types that can support them. Therefore, it
is safe for code to involve operations not present on all iterators (such as +=) so
long as it is within the body of an appropriately-guarded if constexpr.
However, there are downsides. Using constexpr if in this way is only possible
when the difference in the generic component can be expressed entirely within
the body of the function template. We still need EnableIf in the following
situations: • Different “interfaces” are involved
• Different class definitions are needed

• No valid instantiation should exist for certain template argument lists.
It is tempting to handle that last situation with the following pattern: Click here
to view code image
template
void f(T p) {
if constexpr (condition::value) {
// do something here…
}
else {
// not a T for which f() makes sense:
static_assert(condition::value, "can’t call f() for such a T");
}
}

Doing so is not advisable because it doesn’t work well with SFINAE: The
function f() is not removed from the candidates list and therefore may
inhibit another overload resolution outcome. In the alternative, using
EnableIf f() would be removed altogether when substituting
EnableIf<…> fails substitution.

20.3.4 Concepts
The techniques presented so far work well, but they are often somewhat clumsy,
may use a fair amount of compiler resources, and, in error cases, may lead to
unwieldy diagnostics. Many generic library authors are therefore looking
forward to a language feature that achieves the same effect more directly. A
feature called concepts will likely be added to the language for that reason; see
Section 6.5 on page 103, Section 18.4 on page 377, and Appendix E.
For example, we expect our overloaded container constructors would
simply look as follows: Click here to view code image
typeoverload/container4.hpp
template
class Container {
public:
//construct from an input iterator sequence:
template
requires IsInputIterator
Container(Iterator first, Iterator last);
// construct from a random access iterator sequence:
template
requires IsRandomAccessIterator

Container(Iterator first, Iterator last);
// convert to a container so long as the value types are convertible:
template
requires IsConvertible
operator Container() const;
};

The requires clause (discussed in Section E.1 on page 740) describes the
requirements of the template. If any of the requirements are not satisfied, the
template is not considered a candidate. It is therefore a more direct expression of
the idea expressed by EnableIf, supported by the language itself.
The requires clause has additional benefits over EnableIf. Constraint
subsumption (described in Section E.3.1 on page 744) provides an ordering
among templates that differ only in their requires clauses, eliminating the need
for tag dispatching. Additionally, a requires clause can be attached to a
nontemplate. For example, to provide a sort() member function only when
the type T is comparable with <: Click here to view code image
template
class Container {
public:
…
requires HasLess
void sort() {
…
}
};

20.4 Class Specialization
Class template partial specializations can be used to provide alternate,
specialized implementations of a class template for specific template arguments,
much like we used overloading for function templates. And, like overloaded
function templates, it can make sense to differentiate those partial specializations
based on properties of the template arguments. Consider a generic
Dictionary class template with key and value types as its template
parameters. A simple (but inefficient) Dictionary can be implemented so
long as the key type provides just an equality operator: Click here to view code
image
template

class Dictionary
{
private:
vector> data;
public:
//subscripted access to the data:
value& operator[](Key const& key)
{
// search for the element with this key:
for (auto& element : data) {
if (element.first == key){
return element.second;
}
}
// there is no element with this key; add one
data.push_back(pair(key, Value()));
return data.back().second;
}
…
};

If the key type supports a < operator, we can provide a more efficient
implementation based on the standard library’s map container. Similarly, if the
key type supports hashing operations, we can provide an even more efficient
implementation based on the standard library’s unordered_map.

20.4.1 Enabling/Disabling Class Templates
The way to enable/disable different implementations of class templates is to use
enabled/disabled partial specializations of class templates. To use EnableIf
with class template partial specializations, we first introduce an unnamed,
defaulted template parameter to Dictionary: Click here to view code image
template
class Dictionary
{
… //vector implementation as above
};

This new template parameter serves as an anchor for EnableIf, which now
can be embedded in the template argument list of the partial specialization for
the map version of the Dictionary: Click here to view code image
template
class Dictionary>>
{
private:
map data;
public:
value& operator[](Key const& key) {
return data[key];
}
…
};

Unlike with overloaded function templates, we don’t need to disable any
condition on the primary template, because any partial specialization takes
precedence over the primary template. However, when we add another
implementation for keys with a hashing operation, we need to ensure that the
conditions on the partial specializations are mutually exclusive: Click here to
view code image
template
class Dictionary
{
… // vector implementation as above
};
template
class Dictionary && !HasHash Key>>> {
{
… // map implementation as above
};
template typename Key, typename Value>
class Dictionary Key, Value,
EnableIf HasHash Key>>>
{
private:
unordered_map Key, Value> data;
public:
value& operator[](Key const& key) {
return data[key];
}
…
};

20.4.2 Tag Dispatching for Class Templates
Tag dispatching, too, can be used to select among class template partial
specializations. To illustrate, we define a function object type

Advance akin to the advanceIter() algorithm used in
earlier sections, which advances an iterator by some number of steps. We
provide both the general implementation (for input iterators) as well as
specialized implementations for bidirectional and random access iterators,
relying on an auxiliary trait BestMatchInSet (described below) to pick the
best match for the iterator’s category tag: Click here to view code image
// primary template (intentionally undefined):
template
::iterator_category,
std::input_iterator_tag,
std::bidirectional_iterator_tag,
std::random_access_iterator_tag>>
class Advance;
// general, linear-time implementation for input iterators:
template
class Advance
{
public:
using DifferenceType =
typename std::iterator_traits::difference_type;
void operator() (Iterator& x, DifferenceType n) const
{
while (n > 0) {
++x;
--n;
}
}
};
// bidirectional, linear-time algorithm for bidirectional iterators:
template
class Advance
{

public:
using DifferenceType =
typename std::iterator_traits::difference_type;
void operator() (Iterator& x, DifferenceType n) const
{
if (n > 0) {
while (n > 0) {
++x;
--n;
}
} else {
while (n < 0) {
--x;
++n;
}
}
}
};
// bidirectional, constant-time algorithm for random access iterators:
template
class Advance
{
public:
using DifferenceType =
typename std::iterator_traits::difference_type;
void operator() (Iterator& x, DifferenceType n) const
{
x += n;
}
}
This formulation is quite similar to that of tag dispatching for function templates.
However, the challenge is in writing the trait BestMatchInSet, which
intends to determine which is the most closely matching tag (of the input,
bidirectional, and random access iterator tags) for the given iterator. In essence,
this trait is intended to tell us which of the following overloads would be picked
given a value of the iterator’s category tag and to report its parameter type: Click

here to view code image
void f(std::input_iterator_tag);
void f(std::bidirectional_iterator_tag);
void f(std::random_access_iterator_tag); The easiest way to emulate
overload resolution is to actually use overload resolution, as
follows: Click here to view code image
// construct a set of match() overloads for the types in Types…:
template
struct MatchOverloads;
// basis case: nothing matched:
template<>
struct MatchOverloads<> {
static void match(…);
};
// recursive case: introduce a new match() overload:
template
struct MatchOverloads : public MatchOverloads {
static T1 match(T1); // introduce overload for T1
using MatchOverloads::match;// collect overloads from bases
};
// find the best match for T in Types…
: template
struct BestMatchInSetT {
using Type = decltype(MatchOverloads::match(declval()));
};
template
using BestMatchInSet = typename BestMatchInSetT::Type; The
MatchOverloads template uses recursive inheritance to declare a
match() function with each type in the input set of Types. Each
instantiation of the recursive MatchOverloads partial specialization
introduces a new match() function for the next type in the list. It
then employs a using declaration to pull in the match() function(s)
defined in its base class, which handles the remaining types in the
list. When applied recursively, the result is a complete set of
match() overloads corresponding to the given types, each of which
returns its parameter type. The BestMatchInSetT template then passes
a T object to this set of overloaded match() functions and produces
the return type of the selected (best) match() function.6 If none of
the functions matches, the void-returning basis case (which uses an
ellipsis to capture any argument) indicates failure.7 To summarize,
BestMatchInSetT translates a function-overloading result into a trait
and makes it relatively easy to use tag dispatching to select among
class template partial specializations.

20.5 Instantiation-Safe Templates

The essence of the EnableIf technique is to enable a particular template or
partial specialization only when the template arguments meet some specific
criteria. For example, the most efficient form of the advanceIter()
algorithm checks that the iterator argument’s category is convertible to
std::random_access_iterator_tag, which implies that the various
random-access iterator operations will be available to the algorithm.
What if we took this notion to the extreme and encoded every operation that
the template performs on its template arguments as part of the EnableIf
condition? The instantiation of such a template could never fail, because
template arguments that do not provide the required operations would cause a
deduction failure (via EnableIf) rather than allowing the instantiation to
proceed. We refer to such templates as “instantiation-safe” templates and sketch
the implementation of such templates here.
We start with a very basic template, min(), which computes the minimum of
two values. We would typically implement such as a template as follows: Click
here to view code image
template
T const& min(T const& x, T const& y)
{
if (y < x) {
return y;
}
return x;
}

This template requires the type T to have a < operator able to compare two T
values (specifically, two T const lvalues) and then implicitly convert the
result of that comparison to bool for use in the if statement. A trait that checks
for the < operator and computes its result type is analogous to the SFINAEfriendly PlusResultT trait discussed in Section 19.4.4 on page 424, but we
show the LessResultT trait here for convenience: Click here to view code
image
typeoverload/lessresult.hpp
#include  // for declval()
#include  // for true_type and false_type
template
class HasLess {
template struct Identity;
template static std::true_type
test(Identity() < std::declval())>*);
template static std::false_type

test(…);
public:
static constexpr bool value = decltype(test(nullptr))::value;
};
template
class LessResultImpl {
public:
using Type = decltype(std::declval() < std::declval());
};
template
class LessResultImpl {
};
template
class LessResultT
: public LessResultImpl::value> {
};
template
using LessResult = typename LessResultT::Type; This trait can
then be composed with the IsConvertible trait to make min()
instantiation-safe: Click here to view code image

typeoverload/min2.hpp
#include "isconvertible.hpp"
#include "lessresult.hpp"
template
EnableIf, bool>,
T const&>
min(T const& x, T const& y)
{
if (y < x) {
return y;
}
return x;
}

It is instructive to try to call this min() function with various types with
different < operators (or missing the operator entirely), as in the following
example: Click here to view code image
typeoverload/min.cpp
#include"min.hpp"
struct X1 { };
bool operator< (X1 const&, X1 const&) { return true; }

struct X2 { };
bool operator<(X2, X2) { return true; }
struct X3 { };
bool operator<(X3&, X3&) { return true; }
struct X4 { };
struct BoolConvertible {
operator bool() const { return true; } // implicit conversion to bool
};
struct X5 { };
BoolConvertible operator< (X5 const&, X5 const&)
{
return BoolConvertible();
}
struct NotBoolConvertible { // no conversion to bool
};
struct X6 { };
NotBoolConvertible operator< (X6 const&, X6 const&)
{
return NotBoolConvertible();
}
struct BoolLike {
explicit operator bool() const { return true; } // explicit conversion
to bool
};
struct X7 { };
BoolLike operator< (X7 const&, X7 const&) { return BoolLike(); }
int main()
{
min(X1(), X1());
min(X2(), X2());
min(X3(), X3());
min(X4(), X4());
min(X5(), X5());
min(X6(), X6());
min(X7(), X7());
}

//
//
//
//
//
//
//

X1 can be passed to min()
X2 can be passed to min()
ERROR: X3 cannot be passed to min()
ERROR: X4 can be passed to min()
X5 can be passed to min()
ERROR: X6 cannot be passed to min()
UNEXPECTED ERROR: X7 cannot be passed to min()

When compiling this program, notice that while there are errors for four of the
different min() calls—for X3, X4, X6, and X7—the errors do not come from
the body of min(), as they would have with the non-instantiation-safe variant.
Rather, they complain that there is no suitable min() function, because the only
option has been eliminated by SFINAE. Clang produces the following
diagnostic: Click here to view code image

min.cpp:41:3: error: no matching function for call to ’min’
min(X3(), X3()); // ERROR: X3 cannot be passed to min
^~~
./min.hpp:8:1: note: candidate template ignored: substitution failure
[with T = X3]: no type named ’Type’ in
’LessResultT’
min(T const& x, T const& y)

Thus, the EnableIf is only allowing instantiation for those template
arguments that meet the requirements of the template (X1, X2, and X5), so we
never get an error from the body of min(). Moreover, if we had some other
overload of min() that might work for these types, overload resolution could
have selected one of those instead of failing.
The last type in our example, X7, illustrates some of the subtleties of
implementing instantiation-safe templates. In particular, if X7 is passed to the
non-instantiation-safe min(), instantiation will succeed. However, the
instantiation-safe min() rejects it because BoolLike is not implicitly
convertible to bool. The distinction here is particularly subtle: An explicit
conversion to bool can be used implicitly in certain contexts, including in
Boolean conditions for control-flow statements (if, while, for, and do), the
built-in !, &&, and || operators, and the ternary operator ?:. In these contexts,
the value is said to be contextually converted to bool.8
However, our insistence on having a general, implicit conversion to bool has
the effect that our instantiation-safe template is overconstrained; that is, its
specified requirements (in the EnableIf) are stronger than its actual
requirements (what the template needs to instantiate properly). If, on the other
hand, we had entirely forgotten the conversion-to-bool requirement, our
min() template would have been underconstrained, and it would have allowed
some template arguments that could cause an instantiation failure (such as X6).
To fix the instantiation-safe min(), we need a trait to determine whether a
type T is contextually convertible to bool. The control-flow statements are not
helpful in defining this trait, because statements cannot occur within a SFINAE
context, nor are the logical operations, which can be overloaded for an arbitrary
type. Fortunately, the ternary operator ?: is an expression and is not
overloadable, so it can be exploited to test whether a type is contextually
convertible to bool: Click here to view code image
typeoverload/iscontextualbool.hpp
#include  // for declval()
#include  // for true_type and false_type

template
class IsContextualBoolT {
private:
template struct Identity;
template static std::true_type
test(Identity()? 0 : 1)>*);
template static std::false_type
test(…);
public:
static constexpr bool value = decltype(test(nullptr))::value;
};
template
constexpr bool IsContextualBool = IsContextualBoolT::value;

With this new trait, we can provide an instantiation-safe min() with the
correct set of requirements in the EnableIf: Click here to view code image
typeoverload/min3.hpp
#include "iscontextualbool.hpp"
#include "lessresult.hpp"
template
EnableIf>,
T const&>
min(T const& x, T const& y)
{
if (y < x) {
return y;
}
return x;
}

The techniques used here to make min() instantiation-safe can be extended
to describe requirements for nontrivial templates by composing various
requirement checks into traits that describe some class of types, such as forward
iterators, and combining those traits within EnableIf. Doing so has the
advantages of both better overloading behavior and the elimination of the error
“novel” that compilers tend to produce while printing errors deep within a nested
template instantiation. On the other hand, the error messages provided tend to
lack specificity regarding which particular operation failed. Moreover, as we
have shown with our small min() example, accurately determining and
encoding the exact requirements of the template can be a daunting task. We
explore debugging techniques that make use of these traits in Section 28.2 on
page 654.

20.6 In the Standard Library
The C++ standard library provides iterator tags for input, output, forward,
bidirectional, and random-access iterator tags, which we have used in our
presentation. These iterator tags are part of the standard iterator traits
(std::iterator_traits) and the requirements placed on iterators, so they
can be safely used for tag dispatching purposes.
The C++11 standard library std::enable_if class template provides the
same behavior as the EnableIfT class template presented here. The only
difference is that the standard uses a lowercase member type named type rather
than our uppercase Type.
Algorithm specialization is used in a number of places in the C++ standard
library. For example, both the std::advance() and std::distance()
have several variants based on the iterator category of their iterator arguments.
Most standard library implementations tend to use tag dispatching, although,
more recently, some have adopted std::enable_if to implement this
algorithm specialization. Moreover, a number of C++ standard library
implementations also use these techniques internally to implement algorithm
specialization for various standard algorithms. For example, std::copy()
can be specialized to call std::memcpy() or std::memmove() when the
iterators refer to contiguous memory and their value types have trivial copyassignment operators. Similarly, std::fill() can be optimized to call
std::memset(), and various algorithms can avoid calling destructors when a
type is known to have a trivial destructor. These algorithm specializations are not
mandated by the C++ standard in the same way that they are for
std::advance() or std::distance(), but implementers have chosen to
provide them for efficiency reasons.
As introduced in Section 8.4 on page 131, the C++ standard library also hints
strongly at the required use of std::enable_if<> or similar SFINAE-based
techniques in its requirements. For example, std::vector has a constructor
template to allow a vector to be built from an iterator sequence: Click here to
view code image
template
vector(InputIterator first, InputIterator second,
allocator_type const& alloc = allocator_type()); with the requirement
that “if the constructor is called with a type InputIterator that
does not qualify as an input iterator, then the constructor shall not
participate in overload resolution” (see §23.2.3 paragraph 14 of
[C++11]). This phrasing is vague enough to allow the most efficient

techniques of the day to be used for the implementation, but at the
time it was added to the standard, the use of std::enable_if<> was
envisioned.

20.7 Afternotes
Tag dispatching has been known in C++ for a long time. It was used in the
original implementation of the STL (see [StepanovLeeSTL]), and is often used
alongside traits. The use of SFINAE and EnableIf is much newer: The first
edition of this book (see [VandevoordeJosuttisTemplates1st]) introduced the term
SFINAE and demonstrated its use for detecting the presence of member types
(for example).
The “enable if” technique and terminology was first published by Jaakko
J¨arvi, Jeremiah Will-cock, Howard Hinnant, and Andrew Lumsdaine in
[OverloadingProperties], which describes the EnableIf template, how to
implement function overloading with EnableIf (and DisableIf) pairs, and
how to use EnableIf with class template partial specializations. Since then,
EnableIf and similar techniques have become ubiquitous in the
implementation of advanced template libraries, including the C++ standard
library. Moreover, the popularity of these techniques motivated the extended
SFINAE behavior in C++11 (see Section 15.7 on page 284). Peter Dimov was
the first to note that default template arguments for function templates (another
C++11 feature) made it possible to use EnableIf in constructor templates
without introducing another function parameter.
The concepts language feature (described in Appendix E) is expected in the
next C++ standard after C++17. It is expected to make many techniques
involving EnableIf largely obsolete. Meanwhile, C++17’s constexpr if
statements (see Section 8.5 on page 134 and Section 20.3.3 on page 474) is also
gradually eroding their pervasive presence in modern template libraries.
1 An better option for swap(), specifically, is to use std::move() to avoid
copies in the primary template.
2 The categories in this case reflect concepts, and inheritance of concepts is
referred to as refinement. Concepts and refinement are detailed in Appendix E.
3 EnableIf can also be placed in a defaulted template parameter, which has
some advantages over placement in the result type. See Section 20.3.2 on page
472 for a discussion of EnableIf placement.
4 Usually, algorithm specialization is used only to provide efficiency gains,

either in computation time or resource usage. However, some specializations
of algorithms also provide more functionality, such as (in this case) the ability
to move backward in a sequence.
5 While a conversion function template does have a return type—the type it is
converting to—the template parameters in that type need to be deducible (see
Chapter 15) for the conversion function template to behave properly.
6 In C++17, one can eliminate the recursion with pack expansions in the base
class list and in a using declaration (Section 4.4.5 on page 65). We
demonstrate this technique in Section 26.4 on page 611.
7 It would be slightly better to provide no result in the case of failure, to make
this a SFINAE-friendly trait (see Section 19.4.4 on page 424). Moreover, a
robust implementation would wrap the return type in something like
Identity, because there are some types—such as array and function types
—that can be parameter types but not return types. We omit these
improvements for the sake of brevity and readability.
8 C++11 introduced the notion of contextual conversion to bool along with
explicit conversion operators. Together, they replace uses of the “safe bool”
idiom ([KarlssonSafeBool]), which typically involves an (implicit) userdefined conversion to a pointer-to-data member. The pointer-to-data member
is used because it can be treated as a bool value but doesn’t have other,
unwanted conversions, such as bool being promoted to int as part of
arithmetic operations. For example, BoolConvertible() + 5 is
(unfortunately) well-formed code.

Chapter 21
Templates and Inheritance
A priori, there might be no reason to think that templates and inheritance interact
in interesting ways. If anything, we know from Chapter 13 that deriving from
dependent base classes forces us to deal carefully with unqualified names.
However, it turns out that some interesting techniques combine these two
features, including the Curiously Recurring Template Pattern (CRTP) and
mixins. In this chapter, we describe a few of these techniques.

21.1 The Empty Base Class Optimization (EBCO)
C++ classes are often “empty,” which means that their internal representation
does not require any bits of memory at run time. This is the case typically for
classes that contain only type members, nonvirtual function members, and static
data members. Nonstatic data members, virtual functions, and virtual base
classes, on the other hand, do require some memory at running time.
Even empty classes, however, have nonzero size. Try the following program if
you’d like to verify this: Click here to view code image
inherit/empty.cpp
#include 
class EmptyClass {
};
int main()
{
std::cout << "sizeof(EmptyClass):" << sizeof(EmptyClass) << ’\n’;
}

For many platforms, this program will print 1 as size of EmptyClass. A few
systems impose more strict alignment requirements on class types and may print
another small integer (typically, 4).

21.1.1 Layout Principles
The designers of C++ had various reasons to avoid zero-size classes. For
example, an array of zerosize classes would presumably have size zero too, but
then the usual properties of pointer arithmetic would no longer apply. For
example, let’s assume ZeroSizedT is a zero-size type: Click here to view code
image
ZeroSizedT z[10];
…
&z[i] - &z[j] //compute distance between pointers/addresses

Normally, the difference in the previous example is obtained by dividing the
number of bytes between the two addresses by the size of the type to which it is
pointing, but when that size is zero this is clearly not satisfactory.
However, even though there are no zero-size types in C++, the C++ standard
does specify that when an empty class is used as a base class, no space needs to
be allocated for it provided that it does not cause it to be allocated to the same
address as another object or subobject of the same type. Let’s look at some
examples to clarify what this empty base class optimization (EBCO) means in
practice. Consider the following program: Click here to view code image
inherit/ebco1.cpp
#include 
class Empty {
using Int = int;// type alias members don’t make a class nonempty
};
class EmptyToo : public Empty {
};
class EmptyThree : public EmptyToo {
};
int main()
{
std::cout << "sizeof(Empty): " << sizeof(Empty) << ’\n’;
std::cout << "sizeof(EmptyToo): " << sizeof(EmptyToo) << ’\n’;
std::cout << "sizeof(EmptyThree): " << sizeof(EmptyThree) << ’\n’;
}

If your compiler implements the EBCO, it will print the same size for every
class, but none of these classes has size zero (see Figure 21.1). This means that

within class EmptyToo, the class Empty is not given any space. Note also that
an empty class with optimized empty bases (and no other bases) is also empty.
This explains why class EmptyThree can also have the same size as class
Empty. If your compiler does not implement the EBCO, it will print different
sizes (see Figure 21.2).
Click here to view code image

Figure 21.1. Layout of EmptyThree by a compiler that implements the EBCO
Click here to view code image

Figure 21.2. Layout of EmptyThree by a compiler that does not implement the
EBCO
Consider an example that runs into a constraint of the EBCO: Click here to view
code image
inherit/ebco2.cpp
#include !
class Empty {
using Int = int; // type alias members don’t make a class nonempty
};
class EmptyToo : public Empty {
};
class NonEmpty : public Empty, public EmptyToo {
};
int main()
{
std::cout <<"sizeof(Empty): " << sizeof(Empty) <<’\n’;
std::cout <<"sizeof(EmptyToo): " << sizeof(EmptyToo) <<’\n’;
std::cout <<"sizeof(NonEmpty): " << sizeof(NonEmpty) <<’\n’;
}

It may come as a surprise that class NonEmpty is not an empty class. After all,
it does not have any members and neither do its base classes. However, the base
classes Empty and EmptyToo of NonEmpty cannot be allocated to the same
address because this would cause the base class Empty of EmptyToo to end up
at the same address as the base class Empty of class NonEmpty. In other

words, two subobjects of the same type would end up at the same offset, and this
is not permitted by the object layout rules of C++. It may be conceivable to
decide that one of the Empty base subobjects is placed at offset “0 bytes” and
the other at offset “1 byte,” but the complete NonEmpty object still cannot have
a size of 1 byte because in an array of two NonEmpty objects, an Empty
subobject of the first element cannot end up at the same address as an Empty
subobject of the second element (see Figure 21.3).
Click here to view code image

Figure 21.3. Layout of NonEmpty by a compiler that implements the EBCO
The rationale for the constraint on the EBCO stems from the fact that it is
desirable to be able to compare whether two pointers point to the same object.
Because pointers are nearly always internally represented as just addresses, we
must ensure that two different addresses (i.e., pointer values) correspond to two
different objects.
The constraint may not seem very significant. However, in practice, it is often
encountered because many classes tend to inherit from a small set of empty
classes that define some common type aliases. When two subobjects of such
classes are used in the same complete object, the optimization is inhibited.
Even with this constraint, the EBCO is an important optimization for template
libraries because a number of techniques rely on the introduction of base classes
simply for the purpose of introducing new type aliases or providing extra
functionality without adding new data. Several such techniques will be described
in this chapter.

21.1.2 Members as Base Classes
The EBCO has no equivalent for data members because (among other things) it
would create some problems with the representation of pointers to members. As
a result, it is sometimes desirable to implement as a (private) base class what
would at first sight be thought of as a member variable. However, this is not
without its challenges.
The problem is most interesting in the context of templates because template
parameters are often substituted with empty class types, but in general we cannot
rely on this rule. If nothing is known about a template type parameter, the EBCO
cannot easily be exploited. Indeed, consider the following trivial example: Click

here to view code image
template
class MyClass {
private:
T1 a;
T2 b;
…
};

It is entirely possible that one or both template parameters are substituted by an
empty class type. If this is the case, then the representation of
MyClass may be suboptimal and may waste a word of memory for
every instance of a MyClass.
This can be avoided by making the template arguments base classes instead:
Click here to view code image
template
class MyClass : private T1, private T2 {
};

However, this straightforward alternative has its own set of problems: • It
doesn’t work when T1 or T2 is substituted with a nonclass type or with a union
type.
• It also doesn’t work when the two parameters are substituted with the same
type (although this can be addressed fairly easily by adding another layer of
inheritance; see page 513).
• The class may be final, in which case attempts to inherit from it will cause
an error.
Even if we satisfactorily addressed these problems, a very serious problem
persists: Adding a base class can fundamentally modify the interface of the given
class. For our MyClass class, this may not seem significant because there are
very few interface elements to affect, but as we see later in this chapter,
inheriting from a template parameter can affect whether a member function is
virtual. Clearly, this approach to exploiting the EBCO is fraught with all kinds of
trouble.
A more practical tool can be devised for the common case when a template
parameter is known to be substituted by class types only and when another
member of the class template is available. The main idea is to “merge” the
potentially empty type parameter with the other member using the EBCO. For
example, instead of writing Click here to view code image
template
class Optimizable {

private:
CustomClass info; // might be empty
void* storage;
…
};

a template implementer would use the following: Click here to view code
image
template
class Optimizable {
private:
BaseMemberPair info_and_storage;
…
};

Even without seeing the implementation of the template BaseMemberPair, it
is clear that its use makes the implementation of Optimizable more verbose.
However, various template library implementers have reported that the
performance gains (for the clients of their libraries) do justify the added
complexity. We explore this idiom further in our discussion of tuple storage in
Section 25.1.1 on page 576.
The implementation of BaseMemberPair can be fairly compact: Click here
to view code image
inherit/basememberpair.hpp
#ifndef BASE_MEMBER_PAIR_HPP
#define BASE_MEMBER_PAIR_HPP
template
class BaseMemberPair : private Base {
private:
Member mem;
public:
// constructor
BaseMemberPair (Base const & b, Member const & m)
: Base(b), mem(m) {
}
// access base class data via first()
Base const& base() const {
return static_cast(*this);
}
Base& base() {
return static_cast(*this);
}
// access member data via second()

Member const& member() const {
return this->mem;
}
Member& member() {
return this->mem;
}
};
#endif // BASE_MEMBER_PAIR_HPP

An implementation needs to use the member functions base() and member()
to access the encapsulated (and possibly storage-optimized) data members.

21.2 The Curiously Recurring Template Pattern
(CRTP)
Another pattern is the Curiously Recurring Template Pattern (CRTP). This oddly
named pattern refers to a general class of techniques that consists of passing a
derived class as a template argument to one of its own base classes. In its
simplest form, C++ code for such a pattern looks as follows: Click here to view
code image
template
class CuriousBase {
…
};
class Curious : public CuriousBase {
…
};

Our first outline of CRTP shows a nondependent base class: The class Curious
is not a template and is therefore immune to some of the name visibility issues of
dependent base classes. However, this is not an intrinsic characteristic of CRTP.
Indeed, we could just as well have used the following alternative outline: Click
here to view code image
template
class CuriousBase {
…
};
template
class CuriousTemplate : public CuriousBase> {

…
};

By passing the derived class down to its base class via a template parameter, the
base class can customize its own behavior to the derived class without requiring
the use of virtual functions. This makes CRTP useful to factor out
implementations that can only be member functions (e.g., constructor,
destructors, and subscript operators) or are dependent on the derived class’s
identity.
A simple application of CRTP consists of keeping track of how many objects
of a certain class type were created. This is easily achieved by incrementing an
integral static data member in every constructor and decrementing it in the
destructor. However, having to provide such code in every class is tedious, and
implementing this functionality via a single (non-CRTP) base class would
confuse the object counts for different derived classes. Instead, we can write the
following template: Click here to view code image
Click here to view code image

inherit/objectcounter.hpp
#include 
template
class ObjectCounter {
private:
inline static std::size_t count = 0; // number of existing objects
protected:
// default constructor
ObjectCounter() {
++count;
}
// copy constructor
ObjectCounter (ObjectCounter const&) {
++count;
}
// move constructor
ObjectCounter (ObjectCounter &&) {
++count;
}
// destructor
~ObjectCounter() {
--count;

}
public:
// return number of existing objects:
static std::size_t live() {
return count;
}
};

Note that we use inline to be able to define and initialize the count member
inside the class structure. Before C++17, we had to define it outside the class
template: Click here to view code image
template
class ObjectCounter {
private:
static std::size_t count; // number of existing objects
…
};
// initialize counter with zero:
template
std::size_t ObjectCounter::count = 0;

If we want to count the number of live (i.e., not yet destroyed) objects for a
certain class type, it suffices to derive the class from the ObjectCounter
template. For example, we can define and use a counted string class along the
following lines: Click here to view code image
inherit/countertest.cpp
#include "objectcounter.hpp"
#include 
template
class MyString : public ObjectCounter> {
…
};
int main()
{
MyString s1, s2;
MyString ws;
std::cout << "num of MyString: "
<< MyString::live() << '\n';
std::cout << "num of MyString: "
<< ws.live() << '\n';
}

21.2.1 The Barton-Nackman Trick
In 1994, John J. Barton and Lee R. Nackman presented a template technique that
they called restricted template expansion (see [BartonNackman]). The technique
was motivated in part by the fact that—at the time—function template
overloading was severely limited1 and namespaces were not available in most
compilers.
To illustrate this, suppose we have a class template Array for which we want
to define the equality operator ==. One possibility is to declare the operator as a
member of the class template, but this is not good practice because the first
argument (binding to the this pointer) is subject to conversion rules that differ
from the second argument. Because operator == is meant to be symmetrical with
respect to its arguments, it is preferable to declare it as a namespace scope
function. An outline of a natural approach to its implementation may look like
the following: Click here to view code image
template
class Array {
public:
…
};
Click here to view code image
template
bool operator== (Array const& a, Array const& b)
{
…
}

However, if function templates cannot be overloaded, this presents a problem:
No other operator == template can be declared in that scope, and yet it is likely
that such a template would be needed for other class templates. Barton and
Nackman resolved this problem by defining the operator in the class as a normal
friend function: Click here to view code image
template
class Array {
static bool areEqual(Array const& a, Array const& b);
public:
…
friend bool operator== (Array const& a, Array const& b){
return areEqual(a, b);
}
};

Suppose this version of Array is instantiated for type float. The friend
operator function is then declared as a result of that instantiation, but note that
this function itself is not an instantiation of a function template. It is a normal
nontemplate function that gets injected in the global scope as a side effect of the
instantiation process. Because it is a nontemplate function, it could be
overloaded with other declarations of operator == even before overloading of
function templates was added to the language. Barton and Nackman called this
restricted template expansion because it avoided the use of a template
operator==(T, T) that applied to all types T (in other words, unrestricted
expansion).
Because
Click here to view code image
operator== (Array const&, Array const&) is defined inside a
class definition, it is implicitly considered to be an inline
function, and we therefore decided to delegate the implementation to
a static member function areEqual, which doesn’t need to be inline.

Name lookup for friend function definitions has changed since 1994, so the
Barton-Nackman trick is not as useful in standard C++. At the time of its
invention, friend declarations would be visible in the enclosing scope of a class
template when that template was instantiated via a process called friend name
injection. Standard C++ instead finds friend function declarations via argumentdependent lookup (see Section 13.2.2 on page 220 for the specific details). This
means that at least one of the arguments of the function call must already have
the class containing the friend function as an associated class. The friend
function would not be found if the arguments were of an unrelated class type that
could be converted to the class containing the friend. For example: Click here to
view code image
inherit/wrapper.cpp
class S {
};
template
class Wrapper {
private:
T object;
public:
Wrapper(T obj) : object(obj) { //implicit conversion from T to
Wrapper
}
friend void foo(Wrapper const&) {

}
};
int main()
{
S s;
Wrapper w(s);
foo(w); // OK: Wrapper is a class associated withw
foo(s); // ERROR: Wrapper is not associated with s
}

Here, the call foo(w) is valid because the function foo() is a friend declared
in Wrapper which is a class associated with the argument w.2 However, in
the call foo(s), the friend declaration of function foo(Wrapper
const&) is not visible because the class Wrapper in which it is defined is
not associated with the argument s of type S. Hence, even though there is a valid
implicit conversion from type S to type Wrapper (through the constructor
of Wrapper), this conversion is never considered because the candidate
function foo() is not found in the first place. At the time Barton and Nackman
invented their trick, friend name injection would have made the friend foo()
visible and the call foo(s) would succeed.
In modern C++, the only advantages to defining a friend function in a class
template over simply defining an ordinary function template are syntactic: friend
function definitions have access to the private and protected members of their
enclosing class and don’t need to restate all of the template parameters of
enclosing class templates. However, friend function definitions can be useful
when combined with the Curiously Recurring Template Pattern (CRTP), as
illustrated in the operator implementations described in the following section.

21.2.2 Operator Implementations
When implementing a class that provides overloaded operators, it is common to
provide overloads for a number of different (but related) operators. For example,
a class that implements the equality operator (==) will likely also implement the
inequality operator (!=), and a class that implements the less-than operator (<)
will likely implement the other relational operators as well (>, <=, >=). In many
cases, the definition of only one of these operators is actually interesting, while
the others can simply be defined in terms of that one operator. For example, the
inequality operator for a class X is likely to be defined in terms of the equality

operator: Click here to view code image
bool operator!= (X const& x1, X const& x2) {
return !(x1 == x2);
}

Given the large number of types with similar definitions of !=, it is tempting to
generalize this into a template: Click here to view code image
template
bool operator!= (T const& x1, T const& x2) {
return !(x1 == x2);
}

In fact, the C++ standard library contains similar such definitions as part of the
 header. However, these definitions (for !=, >, <=, and >=) were
relegated to the namespace std::rel_ops during standardization, when it
was determined that they caused problems when made available in namespace
std. Indeed, having these definitions visible makes it appear that any type has
an != operator (which may fail to instantiate), and that operator will always be
an exact match for both of its arguments. While the first problem can be
overcome through the use of SFINAE techniques (see Section 19.4 on page
416), such that this != definition will only be instantiated for types with a
suitable == operator, the second problem remains: The general != definition
above will be preferred over user-provided definitions that require, for example,
a derived-to-base conversion, which may come as a surprise.
An alternative formulation of these operator templates based on CRTP allows
classes to opt in to the general operator definitions, providing the benefits of
increased code reuse without the side effects of an overly general operator: Click
here to view code image
inherit/equalitycomparable.cpp
template
class EqualityComparable
{
public:
friend bool operator!= (Derived const& x1, Derived const& x2) {
return !(x1 == x2);
}
};
class X : public EqualityComparable
{
public:
friend bool operator== (X const& x1, X const& x2) {

// implement logic for comparing two objects of type X
}
};
int main()
{
X x1, x2;
if (x1 != x2) { }
}

Here, we have combined CRTP with the Barton-Nackman trick.
EqualityComparable<> uses CRTP to provide an operator!= for its
derived class based on the derived class’s definition of operator==. It
actually provides that definition via a friend function definition (the BartonNackman trick), which gives the two parameters to operator!= equal
behavior for conversions.
CRTP can be useful when factoring behavior into a base class while retaining
the identity of the eventual derived class. Along with the Barton-Nackman trick,
CRTP can provide general definitions for a number of operators based on a few
canonical operators. These properties have made CRTP with the BartonNackman trick a favorite technique for authors of C++ template libraries.

21.2.3 Facades
The use of CRTP and the Barton-Nackman trick to define some operators is a
convenient shortcut. We can take this idea further, such that the CRTP base class
defines most or all of the public interface of a class in terms of a much smaller
(but easier to implement) interface exposed by the CRTP derived class. This
pattern, called the facade pattern, is particularly useful when defining new types
that need to meet the requirements of some existing interface—numeric types,
iterators, containers, and so on.
To illustrate the facade pattern, we will implement a facade for iterators,
which drastically simplifies the process of writing an iterator that conforms to
the requirements of the standard library. The required interface for an iterator
type (particularly a random access iterator) is quite large. The following
skeleton for class template IteratorFacade demonstrates the requirements
for an iterator interface: Click here to view code image
Click here to view code image

inherit/iteratorfacadeskel.hpp
template
class IteratorFacade
{
public:
using value_type = typename std::remove_const::type;
using reference = Reference;
using pointer = Value*;
using difference_type = Distance;
using iterator_category = Category;
// input iterator interface:
reference operator *() const { … }
pointer operator ->() const { … }
Derived& operator ++() { … }
Derived operator ++(int) { … }
friend bool operator== (IteratorFacade const& lhs,
IteratorFacade const& rhs) { … }
…
// bidirectional iterator interface:
Derived& operator --() { … }
Derived operator --(int) { … }
// random access iterator interface:
reference operator [](difference_type n) const { … }
Derived& operator +=(difference_type n) { … }
…
friend difference_type operator -(IteratorFacade const& lhs,
IteratorFacade const& rhs) { … }
friend bool operator <(IteratorFacade const& lhs,
IteratorFacade const& rhs) { … }
…
};

We’ve omitted some declarations for brevity, but even implementing every one
of those listed for every new iterator is quite a chore. Fortunately, that interface
can be distilled into a few core operations: • For all iterators:
– dereference(): Access the value to which the iterator refers (typically
used via operators * and ->).
– increment(): Move the iterator to refer to the next item in the sequence.
– equals(): Determine whether two iterators refer to the same item in a
sequence.
• For bidirectional iterators:
– decrement(): Move the iterator to refer to the previous item in the list.
• For random-access iterators:

– advance(): Move the iterator n steps forward (or backward).
– measureDistance(): Determine the number of steps to get from one
iterator to another in the sequence.
The role of the facade is to adapt a type that implements only those core
operations to provide the full iterator interface. The implementation
IteratorFacade mostly involves mapping the iterator syntax to the minimal
interface. In the following examples, we use the member functions
asDerived() to access the CRTP derived class: Click here to view code
image
Derived& asDerived() { return *static_cast(this); }
Derived const& asDerived() const {
return *static_cast(this);
}

Given that definition, the implementation of much of the facade is
straightforward.3 We only illustrate the definitions for some of the input iterator
requirements; the others follow similarly.
Click here to view code image
reference operator*() const {
return asDerived().dereference();
}
Derived& operator++() {
asDerived().increment();
return asDerived();
}
Derived operator++(int) {
Derived result(asDerived());
asDerived().increment();
return result;
}
friend bool operator== (IteratorFacade const& lhs,
IteratorFacade const& rhs) {
return lhs.asDerived().equals(rhs.asDerived());
}

Defining a Linked-List Iterator
With our definition of IteratorFacade, we can now easily define an iterator
into a simple linked-list class. For example, imagine that we define a node in the
linked list as follows: Click here to view code image
inherit/listnode.hpp
template

class ListNode
{
public:
T value;
ListNode* next = nullptr;
~ListNode() { delete next; }
};

Using IteratorFacade, an iterator into such a list can be defined in a
straightforward manner: Click here to view code image
inherit/listnodeiterator0.hpp
template
class ListNodeIterator
: public IteratorFacade, T,
std::forward_iterator_tag>
{
ListNode* current = nullptr;
public:
T& dereference() const {
return current->value;
}
void increment() {
current = current->next;
}
bool equals(ListNodeIterator const& other) const {
return current == other.current;
}
ListNodeIterator(ListNode* current = nullptr) : current(current) {
}
};

ListNodeIterator provides all of the correct operators and nested types
needed to act as a forward iterator, and requires very little code to implement. As
we will see later, defining more complicated iterators (e.g., random access
iterators) requires only a small amount of extra work.
Hiding the interface
One downside to our implementation of ListNodeIterator is that we were
required to expose, as a public interface, the operations dereference(),
advance(), and equals(). To eliminate this requirement, we can rework
IteratorFacade to perform all of its operations on the derived CRTP class
through a separate access class, which we call IteratorFacadeAccess:
Click here to view code image

Click here to view code image

inherit/iteratorfacadeaccessskel.hpp
// ‘friend’ this class to allow IteratorFacade access to core iterator
operations:
class IteratorFacadeAccess
{
// only IteratorFacade can use these definitions
template
friend class IteratorFacade;
// required of all iterators:
template
static Reference dereference(Iterator const& i) {
return i.dereference();
}
…
// required of bidirectional iterators:
template
static void decrement(Iterator& i) {
return i.decrement();
}
// required of random-access iterators:
template
static void advance(Iterator& i, Distance n) {
return i.advance(n);
}
…
};

This class provides static member functions for each of the core iterator
operations, calling the corresponding (nonstatic) member function of the
provided iterator. All of the static member functions are private, with the access
only granted to IteratorFacade itself. Therefore, our
ListNodeIterator can make IteratorFacadeAccess a friend and
keep private the interface needed by the facade: Click here to view code image
friend class IteratorFacadeAccess;

Iterator Adapters
Our IteratorFacade makes it easy to build an iterator adapter that takes an
existing iterator and exposes a new iterator that provides some transformed view
of the underlying sequence. For example, we might have a container of Person

values: Click here to view code image
inherit/person.hpp
struct Person {
std::string firstName;
std::string lastName;
friend std::ostream& operator<<(std::ostream& strm, Person const& p) {
return strm << p.lastName << ", " << p.firstName;
}
};

However, rather than iterating over all of the Person values in the container,
we only want to see the first names. In this section, we develop an iterator
adapter called ProjectionIterator that allows us “project” the values of
an underlying (base) iterator to some pointer-to-data member, for example,
Person::firstName.
A ProjectionIterator is an iterator defined in terms of the base iterator
(Iterator) and the type of value that will be exposed by the iterator (T): Click
here to view code image
inherit/projectioniteratorskel.hpp
template
class ProjectionIterator
: public IteratorFacade<
ProjectionIterator,
T,
typename std::iterator_traits::iterator_category,
T&,
typename std::iterator_traits::difference_type>
{
using Base = typename std::iterator_traits::value_type;
using Distance =
typename std::iterator_traits::difference_type;
Iterator iter;
T Base::* member;
friend class IteratorFacadeAccess
… //implement core iterator operations for IteratorFacade
public:
ProjectionIterator(Iterator iter, T Base::* member)
: iter(iter), member(member) { }
};
template

auto project(Iterator iter, T Base::* member) {
return ProjectionIterator(iter, member);
}

Each projection iterator stores two values: iter, which is the iterator into the
underlying sequence (of Base values), and member, a pointer-to-data member
describing which member to project through. With that in mind, we consider the
template arguments provided to the IteratorFacade base class. The first is
the ProjectionIterator itself (to enable CRTP). The second (T) and
fourth (T&) arguments are the value and reference types of our projection
iterator, defining this as a sequence of T values.4 The third and fifth arguments
merely pass through the category and difference types of the underlying iterator.
Therefore, our projection iterator will be an input iterator when Iterator is an
input iterator, a bidirectional iterator when Iterator is a bidirectional iterator,
and so on. A project() function makes it easy to build projection iterators.
The only missing pieces are the implementations of the core requirements for
IteratorFacade. The most interesting is dereference(), which
dereferences the underlying iterator and then projects through the pointer-to-data
member: Click here to view code image
T& dereference() const {
return (*iter).*member;
}

The remaining operations are implemented in terms of the underlying iterator:
Click here to view code image
void increment() {
++iter;
}
bool equals(ProjectionIterator const& other) const {
return iter == other.iter;
}
void decrement() {
--iter;
}

For brevity, we’ve omitted the definitions for random access iterators, which
follow analogously.
That’s it! With our projection iterator, we can print out the first names of a
vector containing Person values: Click here to view code image
inherit/projectioniterator.cpp
#include 

#include 
#include 
int main()
{
std::vector authors = { {"David", "Vandevoorde"},
{"Nicolai", "Josuttis"},
{"Douglas", "Gregor"} };
std::copy(project(authors.begin(), &Person::firstName),
project(authors.end(), &Person::firstName),
std::ostream_iterator(std::cout, "\n"));
}

This program produces: David
Nicolai
Douglas
The facade pattern is particularly useful for creating new types that conform to
some specific interface. New types need only expose some small number of core
operations (between three and six for our iterator facade) to the facade, and the
facade takes care of providing a complete and correct public interface using a
combination of CRTP and the Barton-Nackman trick.

21.3 Mixins
Consider a simple Polygon class that consists of a sequence of points: Click
here to view code image
class Point
{
public:
double x, y;
Point() : x(0.0), y(0.0) { }
Point(double x, double y) : x(x), y(y) { }
};
class Polygon
{
private:
std::vector points;
public:
… //public operations
};

This Polygon class would be more useful if the user could extend the set of
information associated with each Point to include application-specific data

such as the color of each point, or perhaps associate a label with each point. One
option to make this extension possible would be to parameterize Polygon
based on the type of the point: Click here to view code image
template
class Polygon
{
private:
std::vector

points; public: … //public operations }; Users could conceivably create their own Point-like data type that provided the same interface as Point but includes other application-specific data, using inheritance: Click here to view code image class LabeledPoint : public Point { public: std::string label; LabeledPoint() : Point(), label("") { } LabeledPoint(double x, double y) : Point(x, y), label("") { } }; This implementation has its shortcomings. For one, it requires that the type Point be exposed to the user so that the user can derive from it. Also, the author of LabeledPoint needs to be careful to provide exactly the same interface as Point (e.g., inheriting or providing all of the same constructors as Point), or LabeledPoint will not work with Polygon. This constraint becomes more problematic if Point changes from one version of the Polygon template to another: The addition of a new Point constructor could require each derived class to be updated. Mixins provide an alternative way to customize the behavior of a type without inheriting from it. Mixins essentially invert the normal direction of inheritance, because the new classes are “mixed in” to the inheritance hierarchy as base classes of a class template rather than being created as a new derived class. This approach allows the introduction of new data members and other operations without requiring any duplication of the interface. A class template that supports mixins will typically accept an arbitrary number of extra classes from which it will derive: Click here to view code image template class Point : public Mixins… { public: double x, y; Point() : Mixins()…, x(0.0), y(0.0) { } Point(double x, double y) : Mixins()…, x(x), y(y) { } }; Now, we can “mix in” a base class containing a label to produce a LabeledPoint: Click here to view code image class Label { public: std::string label; Label() : label("") { } }; using LabeledPoint = Point


Source Exif Data:
File Type                       : PDF
File Type Extension             : pdf
MIME Type                       : application/pdf
PDF Version                     : 1.4
Linearized                      : No
Author                          : David Vandevoorde & Nicolai M. Josuttis & Douglas Gregor
Create Date                     : 2017:09:20 12:47:02+00:00
Producer                        : calibre 3.7.0 [https://calibre-ebook.com]
Title                           : C++ Templates The Complete Guide
Description                     : 
Creator                         : David Vandevoorde, Nicolai M. Josuttis, Douglas Gregor
Publisher                       : Addison Wesley
Subject                         : 
Date                            : 2018:09:15 00:00:00+00:00
Language                        : en
Metadata Date                   : 2017:09:20 12:47:02.967556+00:00
Timestamp                       : 2017:09:20 12:45:05.547300+00:00
Page Count                      : 2543
EXIF Metadata provided by
EXIF.tools

Navigation menu