C++ S: The Guide S

c-s--guide-2nd

C-s-The--Guide

C%2B%2B%20s_%20The%20%20Guide%2C%20David%20Vandevoorde%2C%20Nicolai%20M.%20Josuttis%2C%20Douglas%20Gregor%2C%20(

User Manual:

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

DownloadC++ S: The  Guide S
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.3
11.4
11.5
11.6
11.7

11.2.1 Type Traits
11.2.2 std::addressof()
11.2.3 std::declval()
Perfect Forwarding Temporaries
References as Template Parameters
Defer Evaluations
Things to Consider When Writing Generic Libraries
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.5

14.6
14.7
14.8

14.4.3 Iterated Instantiation
Explicit Instantiation
14.5.1 Manual Instantiation
14.5.2 Explicit Instantiation Declarations
Compile-Time if Statements
In the Standard Library
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.3
24.4
24.5
24.6

24.2.5 Transforming a Typelist
24.2.6 Accumulating Typelists
24.2.7 Insertion Sort
Nontype Typelists
24.3.1 Deducible Nontype Parameters
Optimizing Algorithms with Pack Expansions
Cons-style Typelists
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 template-related
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
void
void
void

foo
foo
foo
foo

(const int &x);
(const int& x);
(int const &x);
(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;
value pointed to can

// the pointer cannot change, but the

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);
foo(void*)

// OK: deduces 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;
…
::max(c1,c2);

// doesn’t provide operator <
// 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);
std::string s;
foo("hello", s);
or std::string

// ERROR: T can be deduced as int or double
//ERROR: T can be deduced as char const[6]

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);
(1)
f();

// OK: deduced T to be int, so that it calls 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;
i auto a = ir;
int

// ir refers to
// a is declared as new object of type

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
C++14

// equivalent since

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);
ints
::max(7.0, 42.0);
deduction)
::max(’a’, ’b’);
deduction)
::max<>(7, 42);
deduction)
::max(7, 42);

// calls the nontemplate for two
// calls max (by argument
//calls max (by argument
// calls max (by argument
// calls max (no argument

deduction)
::max(’a’, 42.7);
ints
}

//calls the nontemplate for two

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);
function perfectly

// both int values match the nontemplate

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);
deduction)
::max(’a’, ’b’);
deduction)

// calls the max (by argument
//calls the max (by argument

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);
nontrivial conversions

//only the nontemplate function allows

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);
template
auto b = ::max(7.2, 4);
template

// uses first
// uses second

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

// ERROR: both

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 =
int b =
auto m1
int

()
7;
42;
= ::max(a,b);

std::string s1 =
"hey"; "
std::string s2 =
"you"; "
auto m2 = ::max(s1,s2);
std::string

// max() for two values of type

// max() for two values of type

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 C-strings:
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 C-strings, 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 three-argument 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);
max(int,int)
}

// OOPS: uses max() instead of

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 compile-time
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.
2 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.

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;
public:
void push(T const& elem);
void pop();
T const& top() const;
bool empty() const {
empty
return elems.empty();
}
};
template

// elements

//
//
//
//

push element
pop element
return top element
return whether the stack is

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;
public:
void push(T const& elem);
void pop();
T const& top()
const;
bool empty() const {
empty
return elems.empty();
}
};

// elements

// push element
// pop element
// return top element
// return whether the stack is

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&);
Stack& operator= (Stack const&);
operator
…
};

which is formally equivalent to:
Click here to view code image
template
class Stack {

// copy constructor
// assignment

…
Stack (Stack const&);
Stack& operator= (Stack const&);
operator
…
};

// copy constructor
// assignment

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();
elems.pop_back();
return elem;
}

// save copy of last element
// remove last element
// 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);
elem
}
…
};

// append copy of passed

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 stringStack;

// stack of ints
// 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)
{
using IntStack = Stack ;
Stack
Stack< int> istack[10];
stacks
IntStack istack2[10];
10 int stacks (same type)
…
}

// parameter s is int stack
// IntStack is another name for
// istack is array of 10 int
// istack2 is also an array of

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;
pointers
Stack> intStackStack;
ints

// stack of float
// stack of stack of

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;
versions

// OK with all C++

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;
no operator<< defined
ps.push({4, 5});
ps.push({6, 7});
std::cout << ps.top().first << ’\n’;
std::cout << ps.top().second << ’\n’;

// note: std::pair<> has
// OK
// OK
// OK
// 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);
for element type

// ERROR: operator<< not supported

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;
operator<< defined
ps.push({4, 5});
ps.push({6, 7});
std::cout <<
ps.top().first << ’\n’;
std::cout <<
ps.top().second << ’\n’;
std::cout << ps << ’\n’;
supported

// std::pair<> has no
// OK
// OK
// OK
// OK
// ERROR: operator<< not
//

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;
public:
void push(std::string const&);
void pop();
std::string const& top() const;
bool empty() const {
stack is empty
return elems.empty();
}
};

// elements

//
//
//
//

push element
pop element
return top element
return whether the

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*);
T* pop();
T* top() const;
bool empty() const {
empty
return elems.empty();
}
};
template
void Stack::push (T* elem)
{
elems.push_back(elem);
}
template
T* Stack::pop ()
{
assert(!elems.empty());
T* p = elems.back();
elems.pop_back();
return p;
general case)
}
template
T* Stack::top () const
{
assert(!elems.empty());
return elems.back();
}

//
//
//
//

push element
pop element
return top element
return whether the stack is

// append copy of passed elem

// remove last element
// and return it (unlike in the

// 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

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;
float, float> mff;
float, int> mfi;
int*, float*> mp;

//
//
//
//

uses
uses
uses
uses

MyClass
MyClass
MyClass
MyClass

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

// ERROR: matches MyClass
//
and MyClass
// 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);
void pop();
T const& top() const;
bool empty() const {
empty

//
//
//
//

push element
pop element
return top element
return whether the stack is

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;
void foo (IntStack const& s);
IntStack istack[10];
stacks of ints

// typedef
// s is stack ofints
// istack is array of 10

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

// alias declaration
// s is stack of ints
// istack is array of 10

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< int> intStack2 = intStack1;
Stack intStack3 = intStack1;

// stack of strings
// OK in all versions
// 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;
public:
Stack () = default;
Stack (T const& elem)
element
: elems({elem}) {
}
…
};

// elements

// initialize stack with one

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

// Stack deduced since

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;
public:
Stack (T elem)
element by value
: elems({elem}) {
arg deduction
}
…
};

// elements
// initialize stack with one
//

to decay on class tmpl

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"};
deduced since C++17

// OK: Stack

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;
public:
Stack (std::string const& elem)

// elements
// 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 stack3(stringStack);
Stack stack4 = {stringStack};

// Stack deduced
// Stack deduced
// 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;
std::size_t numElems;
public:
Stack();
void push(T const& elem);
void pop();
T const& top() const;
bool empty() const {
empty
return numElems == 0;
}
std::size_t size() const {
elements
return numElems;
}
};

// elements
// current number of elements
// constructor
// push element
// pop element
// return top element
//return whether the stack is

//return current number of

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;
ints
Stack
int40Stack;
ints
Stack stringStack;
strings

// stack of up to 20
// stack of up to 40
// stack of up to 40

// 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(),
of source
dest.begin(),
destination
addValue<5,int>);

//start and end
//start of
// 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
not
double process (double v)
parameters
{
return v * VAT;

// ERROR: floating-point values are
//

allowed as template

}
template
not
class MyClass {
parameters
…
};

// ERROR: class-type objects are
//

allowed as template

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";
char const s11[] = "hi";
int main()
{
Message m03;
Message m11;
static char const s17[] = "hi";
Message m17;
}

// external linkage
// internal linkage

//
//
//
//

OK
OK
no
OK

(all versions)
since C++11
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;
argument list
C<42, (sizeof(int) > 4)> c;

// ERROR: first > ends the template
// 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 {
elements
return numElems;
}
};

//return current number of

// 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 {
elements
return numElems;
}

//return current number of

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 numElems;
}

//return current number of elements

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 stringStack;
strings

// stack of up to 20 ints
// stack of up to 40

// 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;
strings

// stack of up to 40

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;
argument

// ERROR: Floating-point nontype

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();
value

// initialize with int 42 and print that

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…);
arguments
}

// call print() for remaining

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’;
remaining types
std::cout << sizeof…(args) << ’\n’;
remaining args
…
}

//print number of
//print number of

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 compile-time

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");
in a separate thread

//call foo(42,"hello")

• 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);
initialized by three arguments

//insert a Customer

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;
string, and character

// t can hold integer,

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 = …;
using const_iterator = …;
…
};

// iterator for read/write access
// 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;
int* ptr;
}

// x has undefined value
// 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 built-in 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{} {
built-in types
}
…
};

// ensures that x is initialized even for

The pre-C++11 syntax
Click here to view code image
MyClass() : x() {
built-in types
}

//ensures that x is initialized even for

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{};
specified
…
};

// zero-initialize x unless otherwise

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
arrays of unknown bounds

// partial spec. for references to

{
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();
extern int x[];
MyClass::print();
foo(a, a, a, x, x, x, x);
}

// uses MyClass
// forward declare array
// uses MyClass

int x[] = {0, 8, 15};
array

// define forward-declared

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;
Stack floatStack;
…
intStack1 = intStack2;
floatStack = intStack1;
different types

// stacks for ints
// stack for floats
// OK: stacks have same type
// ERROR: stacks have

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;
public:
void push(T const&);
void pop();
T const& top() const;
bool empty() const {
empty
return elems.empty();
}

// elements

//
//
//
//

push element
pop element
return top element
return whether the stack is

// 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;
public:
void push(T const&);
void pop();
T const& top() const;
bool empty() const {
empty
return elems.empty();
}

// elements
//
//
//
//

push element
pop element
return top element
return whether the stack is

// 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 floatStack;
…
floatStack = intStack;

// stack for ints
// stack for floats
// 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 floatStack;
…
floatStack = stringStack;
convert to float

// stack of strings
// stack of floats
// ERROR: std::string doesn’t

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&);
void pop();
T const& top() const;
bool empty() const {
empty
return elems.empty();
}

//
//
//
//

push element
pop element
return top element
return whether the stack is

// 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
{
elems.clear();
elements
elems.insert(elems.begin(),
beginning
op2.elems.begin(),
op2
op2.elems.end());
return *this;
}

const& op2)
// remove existing
// insert at the
// all elements from

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’;
std::cout << s1.get() << ’\n’;
BoolString s2("on");
std::cout << s2.get() << ’\n’;

//prints hello
//prints false
//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 << pi << ’\n’;
std::cout << pi << ’\n’;

You can also declare variable templates that are used in different translation units:
Click here to view code 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’;
std::cout << pi << ’\n’;

//outputs a long double
//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{};
zero-initialized
template
constexpr decltype(N) dval = N;
passed value

// array with N elements,

// type of dval depends on

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;
a vector

// integer stack that uses

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;
uses a vector

// integer stack that

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&);
void pop();
T const& top() const;
bool empty() const {
empty
return elems.empty();
}
…
};

//
//
//
//

push element
pop element
return top element
return whether the stack is

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&);
void pop();
T const& top() const;
bool empty() const {
empty
return elems.empty();
}

//
//
//
//

push element
pop element
return top element
return whether the stack is

// 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 fStack;

// stack of ints
// 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 array-topointer 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.
3 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.

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
void f (X& val) {
g(val);
// val is
}
void f (X const& val) {
g(val);
// val is
}
void f (X&& val) {
g(std::move(val)); // val is
std::move() to call g(X&&)
}
int main()
{
X v;
X const c;

to g():
non-const lvalue => calls g(X&)

const lvalue => calls g(X const&)

non-const lvalue => needs

// create variable
// create constant

f(v);
//
calls g(X&)
f(c);
//
=> calls g(X const&)
f(X());
//
g(X&&)
f(std::move(v)); //
calls g(X&&)
}

f() for nonconstant object calls f(X&) =>
f() for constant object calls f(X const&)
f() for temporary calls f(X&&) => calls
f() for movable variable calls f(X&&) =>

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() 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() 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;
X const c;
f(v);
g(X&)
f(c);
calls g(X const&)
f(X());
g(X&&)
f(std::move(v));

// create variable
// create constant
// f() for variable calls f(X&) => calls
// f() for constant calls f(X const&) =>
// f() for temporary calls f(X&&) => calls
// 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);
copying string-CONSTR
Person p2("tmp");
moving string-CONSTR
Person p3(p1);
Person p4(std::move(p1));
}

// init with string object => calls
// init with string literal => calls
// copy Person => calls COPY-CONSTR
// 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);
copying string-CONSTR
Person p2("tmp");
moving string-CONSTR

// init with string object => calls
// init with string literal => calls

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);
Person p4(std::move(p1));

// copy Person => calls COPY-CONSTR
// 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);
TMPL-CONSTR
Person p2("tmp");
TMPL-CONSTR

// init with string object => calls
//init with string literal => calls

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 null-terminated 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));
CONST

// OK: move Person => calls MOVE-

Note that also copying a constant Person works fine:
Click here to view code image
Person const p2c("ctmp");
literal
Person p3c(p2c);
COPY-CONSTR

//init constant object with string
// OK: copy constant Person => calls

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 compile-time
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);
TMPL-CONSTR
Person p2("tmp");
TMPL-CONSTR
Person p3(p1);
Person p4(std::move(p1));
}

// init with string object => calls
// init with string literal => calls
// OK => calls COPY-CONSTR
// 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 compiletime 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.
5 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.

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);
printV(std::string("hi"));
not, move constructor)
printV(returnString());
(if not, move constructor)
printV(std::move(s));

//copy constructor
//copying usually optimized away (if
// copying usually optimized away
// 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");
type char const*
int arr[4];
printV(arr);
type char const*

//decays to pointer so that arg has

// decays to pointer so that arg has

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);
printR(std::string("hi"));
printR(returnString());
printR(std::move(s));

//
//
//
//

no
no
no
no

copy
copy
copy
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);
copying i

// passes reference instead of just

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");
const(&)[3]
int arr[4];
printR(arr);
const(&)[4]

// T deduced as char[3], arg is char

// T deduced as int[4], arg is int

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);
int(&)[4]

// OK: T deduced as int[4], arg is

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);
//
outR(returnConstString()); //
returns const string
outR(std::move(c));
//
6
const
outR("hi");
//

OK: T deduced as std::string const
OK: same if returnConstString()
OK: T deduced as std::string
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) {
reference
…
}

// arg declared as forwarding

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);
the type of arg)
passR(std::string("hi"));
is std::string&&
passR(returnString());
is std::string&&
passR(std::move(s));
is std::string&&
passR(arr);
the type of arg)

// OK: T deduced as std::string& (also
// OK: T deduced as std::string, arg
// OK: T deduced as std::string, arg
// OK: T deduced as std::string, arg
// OK: T deduced as int(&)[4] (also

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);
printT(std::cref(s));

//pass s by reference
// 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 
#include 
#include 

// for std::cref()

void printString(std::string const& s)
{
std::cout << s << ’\n’;
}
template
void printT (T arg)
{
printString(arg);
std::string
}

// might convert arg back to

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")) …
if (isless(std::cref(s) < std::string("world"))) …

//ERROR
//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 call-byvalue:
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
instantiation):
template<>
struct IsPrime<0> { static
template<>
struct IsPrime<1> { static
template<>
struct IsPrime<2> { static
template<>
struct IsPrime<3> { static

endless recursion with template

constexpr bool value = false; };
constexpr bool value = false; };
constexpr bool value = true; };
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)
: doIsPrime(p,p/2);
divisor from p/2
}

// handle special cases
// start recursion with

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);
if in namespace scope

// evaluated at compile time

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);
running time
}

// evaluated at compile or

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 on-demand
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);
std::cout << len("tmp");

// OK: only len() for array matches
//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);
size_type matches

// OK: only len() for a type with

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);
found

// ERROR: no matching len() function

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);
std::cout << len("tmp");
std::vector v;
std::cout << len(v);
size_type is best match
int* p;
std::cout << len(p);
std::allocator x;
std::cout << len(x);
best,

// OK: len() for array is best match
//OK: len() for array is best match

// OK: len() for a type with

// OK: only fallback len() matches

// ERROR: 2nd len() function matches

//

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 best-known

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’;
x has no size()

//ERROR: len() selected, but

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 userdefined 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 compiletime 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-of-class
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);
double
}

// call function template for type

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/gcc61include/bits/predefined_ops.h: In instantiation of 'bool __gnu_cxx
::__ops::_Iter_pred<_Predicate>::operator()
(_Iterator) [with _Iterator = std::_Rb_tree_i
terator, doubl
::]':
6 /cygdrive/p/gcc/gcc61include/bits/stl_algo.h:104:42: required from '_InputIterator
std::__find_if(_InputIterator, _InputIterator, _Predicate, std:
[with _InputIterator = std::_Rb_tree_iterator, double> >; _Predicate = __gnu_cxx::__ops::_Iter_pred<
 >]'
7 /cygdrive/p/gcc/gcc61include/bits/stl_algo.h:161:23: required from '_Iterator std::__
find_if(_Iterator, _Iterator, _Predicate) [with _Iterator = std
pair, double> >; _Predic
Iter_pred >]'
8 /cygdrive/p/gcc/gcc61include/bits/stl_algo.h:3824:28: required from '_IIter std::find
_if(_IIter, _IIter, _Predicate) [with _IIter = std::_Rb_tree_it
std::__cxx11::basic_string, double> >; _Predicate = main(
]'
9
errornovel1.cpp:13:29:
required from here
10 /cygdrive/p/gcc/gcc61include/bits/predefined_ops.h:234:11: error: no match for call to
'(main()::
) (std::pair&)'

11
{ return bool(_M_pred(*__it)); }
12 ^~~~~~~~~~~~~~~~~~~~
13 /cygdrive/p/gcc/gcc61include/bits/predefined_ops.h:234:11: note: candidate: bool (*)
(
const string&) {aka bool (*)
(const std::__cxx11::basic_string&)} 
14 /cygdrive/p/gcc/gcc61include/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
std::__cxx11::basic_string, double>' to 'const string& {a
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
_Kty,_Ty>' 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 userdefined-conversion 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 functi
ion '_InIt std::_Find_if_unchecked>>>,
18
_Mytree=std::_Tree_val>>,
19
_Pr=main::

20
]
21 main.cpp(13): note: see reference to function template instantiati
>
(_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/gcc61include/bits/unordered_set.h:95:63: required from 'class
std::
unordered_set'
8
errornovel2.cpp:28:47:
required from here
9
/cygdrive/p/gcc/gcc61include/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/gcc61include/bits/move.h:57:0,
18
from /cygdrive/p/gcc/gcc61include/bits/stl_pair.h:59,
19
from /cygdrive/p/gcc/gcc61include/bits/stl_algobase.h:64,
20
from /cygdrive/p/gcc/gcc61include/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/gcc61include/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/gcc61include/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
template
class MyClass {
…
};

// primary class

template<>
specialization
class MyClass {
…
};

// explicit

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
class MyClass {

// partial specialization

…
};
template
class MyClass {
…
};

// partial specialization

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 {};
class C
void f(int p)
function f()

// definition (and declaration) of

{

//definition (and declaration) of

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 const* cp;
extern C elems[10];
extern int arr[];

//
//
//
//

C is an incomplete type
cp is a pointer to an incomplete type
elems has an incomplete type
arr has an incomplete type

…
class C { };
cpand elems
int arr[10];

// C now is a complete type (and therefore
// no longer refer to an incomplete type)
// 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 pointer-to-function or referenceto-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);
parameter *current for op

// call operator() with

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 
#include 

// for std::invoke()
// for std::forward()

template
decltype(auto) call(Callable&& op, Args&&… args)
{
return std::invoke(std::forward(op),
callable with
std::forward(args)…);
additional args
}

//passed
// any

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 
#include 
#include 
invoke_result<>

// for std::invoke()
// for std::forward()
// for std::is_same<> and

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 compile-time
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
make_unsigned_t
(hopefully error)

// unsigned int
// undefined behavior

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

// int&&
// int const&&
// int const& (lvalue-

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
can assign an int to an int)
is_assignable_v
= 42)

// yields true (generally, you
// yields false (can’t call 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

For the same reason:
Click here to view code image

// yields true

is_swappable_v
lvalues)
is_swappable_v
the previous check)
is_swappable_with_v
category into account)

// yields true (assuming
// yields true (equivalent to
// yields false (taking value

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)
{
g(std::forward(t));
argument t to g()
}

// t is forwarding reference
// perfectly forward passed

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: "
’\n’;
}
int main()
{
std::cout << std::boolalpha;
int i;
int& r = i;
tmplParamIsReference(i);
tmplParamIsReference(r);
tmplParamIsReference(i);
tmplParamIsReference(r);

<<

//
//
//
//

std::is_reference_v <<

false
false
true
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;
RefMem rm3;
RefMem rm4;

// OK
// ERROR: invalid default value for N
// 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
class Arr {
private:
std::vector elems;
public:
Arr() : elems(SZ) {
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;
of class std::vector<>

// compile-time ERROR deep in the code

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;
incomplete types
};

// only possible if Cont accepts

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
template
class Data {
public:

// a namespace scope class

static constexpr bool copyable = true;
…
};
template
template
void log (T x) {
…
}
template
template (since C++14)
T zero = 0;

// a namespace scope function

// a namespace scope variable

template
// a namespace scope variable
template (since C++14)
bool dataCopyable = Data::copyable;
template
template
using DataList = Data;

// a namespace scope alias

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
template definition
class Node {
…
};
template
implicitly inline)
T* alloc() {
definition
…
}

// an in-class member class

// an in-class (and therefore
//member function template

template
(since C++14)
static T zero = 0;
template
using NodePtr = Node*;
};

// a member variable template

// a member alias template

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
template
class List {
public:
List() = default;
is defined

// a namespace scope class

// because a template constructor

template
class Handle;

// another member class template,
// without its definition

template
List (List const&);

// a member function template
// (constructor)

template
(since C++14)
static U zero;
};

// a member variable template

template
template definition
template
class List::Handle {
…
};

// out-of-class member class

template
// out-of-class member function
template definition
template
List::List (List const& b)
{
…
}
template
template definition
template
U List::zero = 0;

// out-of-class static data member

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{});
built-in types

// T{} is zero for

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());
built-in types

// T() is zero for

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);
fill(array);
for Value is used
}

// OK: default constructor not used
// ERROR: undefined default constructor

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;
template
void open();
template
enum Wood : unsigned char;
class template
static double totalWeight;
in class template
};

// ordinary class in class
// ordinary function in class
// ordinary enumeration type in
// ordinary static data member

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();
Dynamic

// OK: one destructor per instance of

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
declaration of the

// refers to the same entity as a

void external();
file

// same name (and scope) in another

template
same name in
static void internal();

// unrelated to a template with the

template
declaration
static void internal();

// redeclaration of the previous

namespace {
template
the same name
void otherInternal();
similarly appears
}
namespace {
template
template declaration
void otherInternal();
}

// another file

// also unrelated to a template with
// in another file, even one that
//in an unnamed namespace

// redeclaration of the previous

struct {
template void f(T) {}
redeclared
} x;

//no linkage: cannot be

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;
template
template class Box;
specialize

// OK: primary

template void translate(T);
template
template void translate(T);
allowed for functions

// OK: primary

// ERROR: does not

// ERROR: not

template constexpr T zero = T{};
template
template constexpr T zero = T{};
not specialize

// OK: primary
// ERROR: does

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>
third one
class Structure;

//the first parameter is used
//in the declaration of the
// in the declaration of the

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;
allocptr”
friend class Allocator;
Allocator”

// ERROR: use “Allocator*
// ERROR: use “friend

…
};

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
class Y;

// a nontype parameter of pointer type

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;
int*
template class Lexer;
redeclaration

// buf is really an

template struct FuncWrap;
pointer to

// fun really has

template struct FuncWrap;
redeclaration

// OK: this is a

// function type
// OK: this is a

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; }
to an integer
~LocalIncrement() { Counter = Counter - 1; }
};

//OK: reference

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>
void f(C* p);

// OK

template struct C>
not valid here
void f(C* p);

// ERROR: struct

template union C>
not valid here
void f(C* p);

// ERROR: union

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>
C++17
void f(C* p);

// OK since

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>
class Lexer {

// OK

static T* storage;
cannot be used here
…
};

// ERROR: a template template parameter

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
pack named Types
class Tuple;

// declares a template parameter

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;
argument
using IntCharTuple = Tuple;
arguments
using IntTriple = Tuple;
arguments

// OK: one template
// OK: two template
// OK: three template

using EmptyTuple = Tuple<>;
arguments

// OK: zero template

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;
matrix

// OK: 3x3

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);
argument
::max(1.0, -3.0);
deduced to be double
::max(1.0, 3.0);

// explicitly specify template
// template argument is implicitly
// 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);
because N

// useless declaration
// 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);
apply(&multi, 7);
}

// OK
// 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 constant-expression

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;
int a;
C* c2;

// integer type
// address of an external variable

void f();
void f(int);
C* c3;
resolution selects

// name of a function: overload
// 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;
variable/function names

// static class members are acceptable

C* c6;
constant

// an example of a pointer-to-member

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;
Message msg11;
Message msg17;

// OK in all versions
// OK since C++11
// 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;
aren’t acceptable either

// ERROR: addresses of array elements

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>
parameter
class Rel {
…
};

// Cont expects one

Rel rel;
std::list has more than

// ERROR before C++17:
//

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>
number of
class Rel {
…
};
Rel rel;
template parameters

// Cont expects any
// type parameters

// OK: std::list has two
//

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);
template void f(I);

// #1
// #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 move-assignment
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 pack-expansion 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… {
double x, y, z;
public:
Point() : Mixins()… { }
expansion

//base class pack expansion

// base class initializer pack

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;
and Label

// inherits from both Color

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 copy-initializes 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 C-style 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 element-wise 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 welldefined (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, valueinitialization.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[n1], 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;
Factory
friend class Node;
};

// OK even if first declaration of
// 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) {
different function ::feed()
…
}
};
int main()
{
Creator one;
feed(one);
::feed(Creator)
Creator two;
feed(two);
::feed(Creator)
}

//every T instantiates a

// instantiates

// instantiates

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 typesafe 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.
12 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.

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 literal-operator-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;
D::x = 2;
scope
}

// finds B::i
// ERROR: does not find ::x in the enclosing

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)
{
if (count < 0) {
int count = 1;
lookup_example(count);
#3
}
return count + ::count;
refers to #2;
}

// #2

// #3
// unqualified count refers to

// the first (unqualified) count
//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);
f(N::e1);
N::f(),
}

// qualified function name: no ADL
// ordinary lookup finds ::f() and ADL finds
//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
using Type = T;
Node* next;
//
instantiation
Node* previous; //
instantiation
Node* parent;
//
specialization
};

Node {
Node refers to a current
Node refers to a current
Node refers to an unknown

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* c2;
instantiation
I* i;
};
struct J {
C* c;
C* c2;
instantiation
I* i;
specialization,
JJ* j;
};
};

// C refers to a current instantiation
// C refers to a current
// I refers to a current instantiation

//C refers to a current instantiation
// C refers to a current
// I refers to an unknown
// because I does not enclose
// 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 contextfree 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 right-shift
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 };
};
template
class Victim {
public:
int y;
void poof() {
Trap::x * y;
}
};
template<>
class Trap {
public:
using x = int;
};

// #1 x is not a type here

// #2 declaration or multiplication?

//evil specialization!
// #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;
Magic* plink;
a
};
template

// ERROR: not standard
// SYNTAX ERROR: Magic is not
//

known

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 chickenand-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 type-dependent
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
type-dependent
}

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 valuedependent 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 typedependent,
// 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 valuedependent 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 type-dependent. 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 value-dependent 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 instantiationdependent but not value-dependent:
Click here to view code image
template
{
constexpr int
constexpr int
int array[x instantiations
}

void instantiationDependentBound()
x = sizeof(N);
y = sizeof(N) + 1;
y]; // array will have a negative size in all

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> {
really
public:

//not a template case

void f() { basefield = 3; }
inherited member
};

//usual access to

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 {
public:
void f() { basefield = 0; }
};

//dependent base
// #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;
syntax
this->zero();
virtuality
one(e);
argument
}
};

// this->E would not be valid
// D::zero() would inhibit
// one is dependent because its
//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;
scope
void f() { basefield = 0; }
};

// #1 dependent name now in
// #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 HewlettPackard (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;
C* p = 0;
not needed
template
class C {
public:
void f();
};
completed
void g (C& c)
declaration only
{
c.f();
definition;
}
C::f()
template
void C::f()
{
}

// #1 declaration only
// #2 fine: definition of C

// #3 member declaration
// #4 class template definition

// #5 use class template

// #6 use class template
//

will need definition of

//

in this translation unit

//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);
void candidate(int) { }
int main()
{
candidate(42);
be called
}

// #1
// #2

// both previous function declarations can

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 one-argument 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];
fail for N<=0
};
template

// OK here, although would

class Tricky {
public:
void noBodyHere(Safe = 3);
value results in an error
void inclass() {
Danger noBoomYet;
with N<=0
}
struct Nested {
Danger pfew;
with N<=0
};
union {
Danger anonymous;
instantiated with N<=0
int align;
};
void unsafe(T (*p)[N]);
instantiated with N<=0
void error() {
Danger<-1> boom;
compilers detect)
}
};

// OK until usage of default

// OK until inclass() is used

// OK until Nested is used

//due anonymous union:
// OK until Tricky is

// OK until Tricky is

// always ERROR (which not all

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 argumentdependent 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 standardconforming 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 Cfrontbased 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
template void
template void
template void
template void

explicit instantiations:
f(int);
f<>(float);
f(long);
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()
{
// implementation
}

//definition

// ===== 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();
extern template void f();

// declared but not defined
// declared but not defined

// ===== t.cpp:
template void f();
template void f();

// definition
// 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 {
when b is false
static bool f(T p) {
specialization for true)
return p.compare(0) > 0;

//only to be instantiated
//(due to next

}
};
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 day-to-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.
4 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.
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:
g(arr);
// reference parameter:
f(seven); // nonreference parameter:
g(seven); // reference parameter:
f(7);
// nonreference parameter:
g(7);
// reference parameter:
can’t pass 7 to int&

T
T
T
T
T
T

is
is
is
is
is
is

double*
double[20]
int
int const
int
int => ERROR:

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; templateids; 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>());
f(X, Y>());
}

// OK
// 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});
f({’a’, ’e’, ’i’, ’o’, ’u’, 42});
char and int
}

// OK: T is deduced to int
//ERROR: T deduced to both

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…};
array of passed chars
for (char c : chars) {
it (print it here)
std::cout << "’" << c << "’";
}
std::cout << ’\n’;
return …;
}

//initialize
//and use

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 b =
auto c =
’0’>
auto d =
auto e =
defined
auto f =
match

01.3_B7;
0xFF00_B7;
0815_B7;
hello_B7;

// OK: deduces <’0’, ’1’, ’.’, ’3’>
// OK: deduces <’0’, ’x’, ’F’, ’F’, ’0’,
// ERROR: 8 is no valid octal literal
// ERROR: identifier hello_B7 is not

"hello"_B7; //ERROR: literal operator _B7 does not

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
f(i); //
//
f(j); //
//
f(2); //
//
}

j = 0;
argument is an
parameter phas
argument is an
parameter phas
argument is an
parameter phas

lvalue; deduces Tto int&and
type int&
lvalue; deduces Tto int const&
type int const&
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&&)
reference
{
std::remove_reference_t x;
…
}

// p is a forwarding

// 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));
}
void foo()
{

// forward x to g()

C v;
C const c;
forwardToG(v);
forwardToG(c);
forwardToG(C());
forwardToG(std::move(v));

//
//
//
//

eventually
eventually
eventually
eventually

calls
calls
calls
calls

g(C&)
g(C const&)
g(C&&)
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 rvalue-ness. 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);
forwardToG(0);
}

// calls g(int*)
// 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);
forwardToG(nullptr);

// calls g(int*)
// 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&);
type int
template void lvalues(T&);
any type

// accepts lvalues of
// accepts lvalues of

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 templateparameter &&, 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&&);
parameter
X(T&&);
not a function template
template X(X&&);
template parameter template<
typename U> X(U, T&&);
parameter from

// X is not a template
// this constructor is

// X is not a
// T is a template
// 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 compile-time 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));
default

// T() is invalid for T = S, but the
// 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 ill-formed 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);
template
void g(T, …);

//#1

//#2

void test(int i)
{
g(i, i);// ERROR: chooses #1 , but the type T::Nonexistent is
ill-formed
}

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);
deduced,

// the type of parameter p is
// 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);
template T f(T);

// #1
// #2

int main() {
auto x = f(42);
auto y = f<>(42);
}

// calls #1
// 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();
friend int f<>();
};

// OK
// 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();//
template T f();//

#1
#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;
f here
}

// ERROR: there are two possible

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);
to double
}

// OK: 1 and 2 are converted

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;
(auto = int)
auto&& lr = x;
collapsing makes

// OK: rvalue reference binds to an rvalue
// Also OK: auto = int& and reference
//

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:
unsigned int
auto* gp = (void*)nullptr;
// OK:
auto const S::*pm = &X::m;
// OK:

};
constant of type
gp has type void*
pm has type int const

X::*
X xa = X();
argument
int const auto::*pm2 = &X::m;
the “declarator”

// ERROR: auto in template
// ERROR: auto is part of

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;
return r;
}

// valid in C++03 but invalid in C++11

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;
std::is_rvalue_reference::value;
declared)
std::is_same::value;
std::is_same::value;

// false
// true (s as
// false
// 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;
int const& ref = i;
to i

// i has type int
// ref has type int const& and refers

auto x = ref;
independent object

// x1 has type int and is a new

decltype(auto) y = ref;
refers to i

// y has type int const& and also

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;
decltype(auto) r = (x);

// object of type int
// 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});
deduceT({ 1 });

// ERROR
// 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 };
std::initializer_list
deduceT(primes);
std::initializer_list

// primes is
// T deduced as

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 };
auto val { 2 };

// ERROR in C++17
// 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 wellformed. This can produce some interesting cases:13
Click here to view code image
char c;
auto *cp = &c, d = c;
auto e = c, f = c+1;
int

// OK
// ERROR: deduction mismatch char vs.

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;
} else {
return 0;
}
}

// deduces return type double
// 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);
} else {

// ERROR: type of f(n-1) unknown

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;
} else {
return n*f(n-1);
type of n*f(n-1)
}
}

// return type is deduced to be int
// OK: type of f(n-1) is int and so is

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() { }
auto f2() { return; }

// OK: return type is void
// 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 illformed

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();
auto& [ r, s ] = f();

// #1
// #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-tofunction 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{});
closure type

// pass an object of the

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)
the compiler
: _x(x), _y(y) {
}
bool operator() (int i) const {
return i > _x && i < _y;
}
};

//only callable by

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);
void test(DequeStack
{
f1(intStack); // OK: T
std::deque
f2(intStack); // OK: T
f3(intStack); // OK: T
}

// equivalent to f2

intStack)
deduced to int, Cont deduced to
deduced to int
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);
specified, T2 not deduced
C<> c11(22, 44.3, 42);
explicitly specified

// ERROR: only T1 explicitly
// ERROR: neither T1 nor T2

C c12("hi","my");
T3 has default

// OK: T1 and T2 are deduced,

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;
S x{12};
S y(12);
auto z = S{12};
{12};

// deduction guide

// OK since C++17, same as: S x{12};
// OK since C++17, same as: S y(12);
// OK since C++17, same as: auto z = S

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};
a2(42);
a3 = {42};
42;

//
//
//
//

OK
ERROR: not aggregate initialization
OK
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);
A a6 = 42;

// ERROR: not aggregate initialization
// 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;
template explicit Z(T&&) -> Z;

// #1
// #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.
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,
6

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)
{
T tmp(*a);
*a = *b;
*b = tmp;
}

// #1

template
void quickExchange(Array* a, Array* b) //
{
a->exchangeWith(b);
}
void demo(Array* p1, Array* p2)
{
int x=42, y=-7;

#2

quickExchange(&x, &y);
quickExchange(p1, p2);

// uses #1
// 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);
std::cout << f((int*)nullptr);
}

// calls f(T)
// 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);
std::cout << f((int*)nullptr);

// calls f(T)
// 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);
std::cout << f(nullptr);
std::cout << f((int*)nullptr);
}

// calls f(T)
// calls f(T)
// 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};
C x3{std::move(x)};
C const c;
C x4{c};

// prints: template constructor
// prints: move constructor
// prints: copy constructor

C x5{std::move(c)};

// 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)
second template

//for

and
Click here to view code image
f((int*)nullptr, (double*)nullptr)
third template

//for

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());
>)
std::cout << f(Tuple());
(Tuple)
std::cout << f(Tuple());
(Tuple)
}

// calls f<>(Tuple
// calls f<>

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 {
public:
void f();
};

// #2

template<> class S; // #3
template<> class S;
int main()
{
S*
S
available
S*
S
S
available
S
available
}

// ERROR: 0 cannot substitute U

pi;
e1;

// OK: uses #1 , no definition needed
// ERROR: uses #1 , but no definition

pv;
sv;
e2;

// OK: uses #2
// OK: uses #2 , definition available
// ERROR: uses #1 , but no definition

e3;

// ERROR: uses #3 , but no definition

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;
Invalid
template<>
class Invalid;
instantiated

// causes the instantiation of

// ERROR: Invalid already

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];
extern void clear(char*);
int main()
{
clear(buffer);
}
// Translation unit 2:
template
class Danger;
template<>
class Danger {
public:

// uses generic value

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-to-find 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)
{
return 1;
}
template
int f(T*)
{
return 2;

// #1

// #2

}
template<>
{
return
}
template<>
{
return
}

int f(int)

// OK: specialization of #1

3;
int f(int*)

// OK: specialization of #2

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)
{
return 0;
}

// ERROR

(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 {
public:
template
class Inner {
private:
static int count;
};
static int code;
void print() const {
std::cout << "generic";
}
};
template
int Outer::code = 6;

// #1

// #2
// #3
// #4
// #5

// #6

template template
int Outer::Inner::count = 7;
// #7
template<>
class Outer {
public:
template
class Inner {
private:
static int count;
};
void print() const {
}
};

// #8

// #9
//#10
//#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-tomember-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&);
template

// primary

template
T* const& max (T* const&, T* const&);
specialization

// partial

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);
specialize?

// Which primary template does this

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,
defaultCopy,
defaultSwap,
defaultInit,
defaultKill>

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,
defaultCopy,
defaultSwap,
defaultInit,
defaultKill>

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);
template specialization

// NOTE: “in instantiation of function
//

’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 type-checking 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 compile-time
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(c);

// myDraw(GeoObj&) => Line::draw()
// myDraw(GeoObj&) => Circle::draw()

distance(c1,c2);
distance(l,c);

// distance(GeoObj&,GeoObj&)
// distance(GeoObj&,GeoObj&)

std::vector coll;
coll.push_back(&l);
coll.push_back(&c);
drawElems(coll);
GeoObjs
}

//
//
//
//

heterogeneous collection
insert line
insert circle
draw different kinds of

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)
class
{
obj.draw();
}

// GeoObj is abstract base

could conceivably be rewritten as
Click here to view code image
template
void myDraw (GeoObj const& obj)
parameter
{
obj.draw();
}

// GeoObj is template

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(GeoObj&) =>

distance(c1,c2);
(GeoObj1&,GeoObj2&)
distance(l,c);

//distance
// 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-tounderstand 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 = …;
iterator
…

// implementation-specific
// type for constant

vectors
const_iterator begin() const;
collection
const_iterator end() const;
collection
…
};

// iterator for start of
// iterator for end of

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 industrialstrength 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{};
…
return total;

// assume this actually creates a zero value

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};
literal type
};

// ERROR: not a

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};
C++17
};

// OK since

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();
trait function

// init total by

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> {
std::list
using Type = T;
};
…

//partial specialization for

template
struct ElementT {
//partial specialization for
arrays of known bounds
using Type = T;
};
template
struct ElementT {
arrays of unknown bounds
using Type = T;
};
…

//partial specialization for

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
’\n’;
std::cout
’\n’;
std::cout
’\n’;
}

<< "Parameter type: " << typeid(A).name() << ’\n’;
<< "- is int:
" <::value <<
<< "- is const:

" <::value <<

<< "- is pointer: " <::value <<

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{});
whether T is int
}

// choose impl. depending on

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*);
test()
template<…> static std::false_type test(…);

// checking
// 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 constant-expressions, 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 wouldbe 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 
#include 

// for declval
// 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 {
used otherwise
};

//partial specialization,

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 
#include 

// for true_type and false_type
// 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
IsConvertibleT::value
IsConvertibleT::value
IsConvertibleT::value

//yields
//yields
//yields
//yields

true
false
true
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;
std::cout << HasSizeTypeT::value;

// OOPS: prints false
// 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 <<
<<
std::cout <<
<<
’\n’;
std::cout <<
<<
std::cout <<
<<
}

"int::value_type: "
HasTypeT_value_type::value << ’\n’;
"std::vector::value_type: "
HasTypeT_value_type>::value <<
"std::iostream::value_type: "
HasTypeT_value_type::value << ’\n’;
"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 <<
<<
std::cout <<
<<
std::cout <<
<<
’\n’;
}

"int::size: "
HasMemberT_size::value << ’\n’;
"std::vector::size: "
HasMemberT_size>::value << ’\n’;
"std::pair::first: "
HasMemberT_first>::value <<

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 
#include 

// for declval
// 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 
#include 

// for declval
// 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
HasLessT::value
HasLessT::value
HasLessT::value

//yields true
//yields true
//yields false
//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 
#include 

// for declval
// 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 SFINAEfriendly 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 <<
true
cout <<
true
cout <<
false
cout <<
true
}

hasLess(42, type) << ’\n’;

//yields

hasLess(type, type) << ’\n’;

//yields

hasLess(type, type) << ’\n’;

//yields

hasLess(type, "hello") << ’\n’;

//yields

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
’\n’;
cout
’\n’;
cout
’\n’;
cout
’\n’;
}

<< HasLessT::value <<
// true
<< HasLessT::value <<
// true
<< HasLessT::value <<
// false
<< HasLessT::value <<
// 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 ::max(),
char,
typename IfThenElseT ::max(),
short,
typename IfThenElseT ::max(),
int,
typename IfThenElseT
::max(), long,
typename IfThenElseT
::max(),
long long, //then
void
//fallback
>::Type
>::Type
>::Type
>::Type
>::Type;
};

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 
#include 

// for declval
// 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;
time ERROR

// compile-

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 
#include 
bool_constant<>

// for declval
// for true_type, false_type, and

// 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 HasNothrowMove-Constructor. 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 {
types
…
};

//partial specialization for class

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 
#include 
bool_constant<>

// for nullptr_t
// for true_type, false_type, and

// 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 {
default not a pointer
};
template
struct IsPointerT : std::true_type {
specialization for pointers
using BaseT = T; // type pointing to
};

//primary template: by

//partial

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 {
no lvalue reference
};
template
struct IsLValueReferenceT : std::true_type {
lvalue references
using BaseT = T; // type referring to
};

//by default

//unless T is

and rvalue reference types:
Click here to view code image

traits/isrvaluereference.hpp
template
struct IsRValueReferenceT : std::false_type {
no rvalue reference
};
template
struct IsRValueReferenceT : std::true_type {
rvalue reference
using BaseT = T; // type referring to
};

//by default

//unless T is

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 {
not an array
};
template
struct IsArrayT : std::true_type {
specialization for arrays
using BaseT = T;
static constexpr std::size_t size = N;
};

//primary template:

//partial

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 {
default no pointer-to-member
};
template
struct IsPointerToMemberT : std::true_type {
specialization
using MemberT = T;
using ClassT = C;
};

//by

//partial

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 {
no function
};

//primary template:

template
struct IsFunctionT : std::true_type
{
//functions
using Type = R;
using ParamsT = Typelist;
static constexpr bool variadic = false;
};
template
struct IsFunctionT : std::true_type {
functions
using Type = R;
using ParamsT = Typelist;
static constexpr bool variadic = true;
};

//variadic

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>
pointer-to-member
: std::true_type {
};

// classes can have

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 SFINAE-based 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 pointerto-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 read-only parameters by referenceto-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);
(mc1,mc2)
}

// same as foo_core

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 compile-time
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, nonvoid 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 randomaccess 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) {
}
} else {
for ( ; n < 0; --x, ++n) {
}
}

//linear time for positive 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 SFINAE-friendly
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 
#include 

// for declval()
// 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(),
min(X2(),
min(X3(),
min(X4(),
min(X5(),
min(X6(),
min(X7(),
min()
}

X1());
X2());
X3());
X4());
X5());
X6());
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

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 noninstantiation-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 
#include 

// for declval()
// 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 copy-assignment 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) user-defined
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) wellformed 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]
pointers/addresses

//compute distance between

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):
std::cout << "sizeof(EmptyToo):
’\n’;
std::cout << "sizeof(EmptyThree):
’\n’;
}

" << sizeof(Empty) << ’\n’;
" << sizeof(EmptyToo) <<
" << sizeof(EmptyThree) <<

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;
nonempty
};

// type alias members don’t make a class

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;
objects
protected:
// default constructor
ObjectCounter() {

// number of existing

++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 argument-dependent 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 userprovided 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 Barton-Nackman 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 Barton-Nackman 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:16 16:18:52+00:00
Producer                        : calibre 3.7.0 [https://calibre-ebook.com]
Title                           : C++ Templates: The Complete Guide
Description                     : 
Subject                         : 
Creator                         : David Vandevoorde, Nicolai M. Josuttis, Douglas Gregor
Publisher                       : Pearson Education
Date                            : 2017:09:15 00:00:00+03:00
Language                        : en
Identifier Scheme               : isbn
Identifier                      : 9780134778747, B075MJNCCH
Metadata Date                   : 2017:09:16 19:18:52.972000+03:00
ISBN                            : 9780134778747
Isbn                            : 9780134778747
Timestamp                       : 2017:09:16 19:15:29.047000+03:00
Title sort                      : C++ Templates: The Complete Guide
Author sort                     : Vandevoorde, David
Page Count                      : 2606
EXIF Metadata provided by
EXIF.tools

Navigation menu