Variadic Templates
Andrei Alexandrescu Research Scientist Facebook
c 2012 Andrei Alexandrescu, Facebook. 1/34 Twitter stream highlight
“Don’t think I’ll be able to stay up to see whatever Cthuloid-template-horror Andrei Alexandrescu has in store. #GoingNative”
c 2012 Andrei Alexandrescu, Facebook. 2/34 This talk
• Motivation and fundamentals • True variadic functions • std::tuple
c 2012 Andrei Alexandrescu, Facebook. 3/34 Motivation and fundamentals
c 2012 Andrei Alexandrescu, Facebook. 4/34 Motivation
• Define typesafe variadic functions ◦ C99 macros safer than C++03 variadic functions?! ◦ Forwarding with before/after hooks • Define algebraic types without contortions ◦ Sum types (variant) ◦ Product types (tuple) • Specify settings and parameters in policy-based designs
c 2012 Andrei Alexandrescu, Facebook. 5/34 Fundamentals
template
template
c 2012 Andrei Alexandrescu, Facebook. 6/34 A New Kind: Parameter Packs
• Ts is not a type; vs is not a value!
typedef Ts MyList; // error! Ts var; // error! auto copy = vs; // error!
• Ts is an alias for a list of types • vs is an alias for a list of values • Either list may be potentially empty • Both obey only specific actions
c 2012 Andrei Alexandrescu, Facebook. 7/34 Using Parameter Packs
• Apply sizeof... to it
size_t items = sizeof...(Ts); // or vs
• Expand back
template
• That’s about it!
c 2012 Andrei Alexandrescu, Facebook. 8/34 Expansion rules
Use Expansion Ts... T1, ..., Tn Ts&&... T1&&, ..., Tn&& x
• (Please note: ellipses on the right are in a different font)
c 2012 Andrei Alexandrescu, Facebook. 9/34 Expansion loci (1/2)
• Initializer lists any a[] = { vs... }; • Base specifiers template
c 2012 Andrei Alexandrescu, Facebook. 10 / 34 Expansion loci (2/2)
• Template argument lists std::map
c 2012 Andrei Alexandrescu, Facebook. 11 / 34 Multiple expansions
• Expansion proceeds outwards • These are different expansions!
template
c 2012 Andrei Alexandrescu, Facebook. 12 / 34 Per popular demand: VVTTs
template < typename T, template < template
• Yup, this works.
c 2012 Andrei Alexandrescu, Facebook. 13 / 34
How to use variadics?
• Pattern matching!
template
c 2012 Andrei Alexandrescu, Facebook. 15 / 34 True Variadic Functions
c 2012 Andrei Alexandrescu, Facebook. 16 / 34 Typesafe printf
• Stock printf: ◦ Fast ◦ Thread-safe ◦ Convenient ◦ Ubiquitously known ◦ Utterly unsafe • Conventionally: reimplement from first principles
• Here: Add verification and adaptation code
c 2012 Andrei Alexandrescu, Facebook. 17 / 34 Step 1: Add adaptation routines
template
template
template
const char* normalizeArg(const string& arg) { return arg.c_str(); }
c 2012 Andrei Alexandrescu, Facebook. 18 / 34 Preliminary tests
// Not really safe yet template
c 2012 Andrei Alexandrescu, Facebook. 19 / 34 Step 2: Define test for arg-less call
void check_printf(const char * f) { for (; *f; ++f) { if (*f != ’%’ || *++f == ’%’) continue; throw Exc("Bad format"); } }
c 2012 Andrei Alexandrescu, Facebook. 20 / 34 Step 3: Define recursive test
template
c 2012 Andrei Alexandrescu, Facebook. 21 / 34 Step 4: Integration
template
c 2012 Andrei Alexandrescu, Facebook. 22 / 34 Further improvements
• Extend to all types (easy) • Add flags, precision etc (easy but >1 slide) • Allow odd cases (e.g. print long as pointer) • Define safe_scanf • Guard the check:
#ifndef NDEBUG check_printf(f, normalizeArg(ts)...); #endif
c 2012 Andrei Alexandrescu, Facebook. 23 / 34 std::tuple
c 2012 Andrei Alexandrescu, Facebook. 24 / 34 std::tuple
• Largest variadics-related offering in std • “Product type” packing together any number of values of heterogeneous types • Generalizes, plays nice with std::pair • Store layout not specified ◦ + Implementation is free to choose optimally • − Currently neither does ◦ − No prefix/suffix property
c 2012 Andrei Alexandrescu, Facebook. 25 / 34 std::tuple introduction
tuple
c 2012 Andrei Alexandrescu, Facebook. 26 / 34 The usual suspects
• Constructors, assignment • make_tuple • Equality and ordering comparisons • swap
c 2012 Andrei Alexandrescu, Facebook. 27 / 34 Less usual suspects
• pack_arguments • tie • tuple_cat • Allocator constructors, uses_allocator • Range primitives begin, end
c 2012 Andrei Alexandrescu, Facebook. 28 / 34 std::tuple structure
template
• Head is a suffix of the structure • No prescribed layout properties
c 2012 Andrei Alexandrescu, Facebook. 29 / 34 Implementing std::get
• Let’s first implement the kth type
template
c 2012 Andrei Alexandrescu, Facebook. 30 / 34 Implementing std::get: base case
• Shouldn’t be a member! • t.template get<1>(), ew
template
c 2012 Andrei Alexandrescu, Facebook. 31 / 34 Implementing std::get: recursion
template
c 2012 Andrei Alexandrescu, Facebook. 32 / 34 Summary
c 2012 Andrei Alexandrescu, Facebook. 33 / 34 Summary
• Familiar approach: pattern matching with recursion • Yet new, too: expansion rules and loci • True variadic functions finally possible • std::tuple a useful abstraction for product types
c 2012 Andrei Alexandrescu, Facebook. 34 / 34