C++ Metaprogramming - Fedor Pikus - CppCon 2015
C++ Metaprogramming - Fedor Pikus - CppCon 2015
2 Metaprogramming www.mentor.com
What is Metaprogramming?
3 Metaprogramming www.mentor.com
Why use metaprogramming?
4 Metaprogramming www.mentor.com
Tools of metaprogramming
Template:
template <typename T> struct SizeOfT {
enum { value = sizeof(T) };
};
In C++11 can also use static constexpr data members:
— In C++03 static constants (usually) must be defined somewhere
template <typename T> struct SizeOfT {
static constexpr value = sizeof(T);
};
Template metafunction Sizeof<T>::value
— C++11 convention: numeric results are named “value”, type
results are named “type” (improves reusability)
5 Metaprogramming www.mentor.com
Tools of metaprogramming
Template:
template <typename T> struct SizeOfT {
enum { value = sizeof(T) };
};
template <typename T> struct TPtr {
typedef T* type;
};
Template metafunction Sizeof<T>::value
— C++11 convention: numeric results are named “value”, type
results are named “type”
6 Metaprogramming www.mentor.com
Tools of metaprogramming
7 Metaprogramming www.mentor.com
Tools of metaprogramming
Template specializations:
template <typename T> struct IsChar {
enum { value = 0 }; // Works for most types
};
template <> struct IsChar<char> {
enum {value = 1 };
};
8 Metaprogramming www.mentor.com
Tools of metaprogramming
9 Metaprogramming www.mentor.com
Tools of metaprogramming
10 Metaprogramming www.mentor.com
Tools of metaprogramming
12 Metaprogramming www.mentor.com
Not Tools of metaprogramming
Variables
for-loops
13 Metaprogramming www.mentor.com
Tools of metaprogramming
Recursion
Termination is usually done via specialization
Sum(N) = N + (N-1) + (N-2) + … + 1
template <size_t N> struct Sum {
enum { value = N + Sum<N-1>::value };
};
template <> struct Sum<1> {
enum { value = 1 };
};
Compilers implement this reasonably fast but have
recursion depth limits (constexpr functions often have
higher limits and are much faster)
14 Metaprogramming www.mentor.com
Types of metaprograms
15 Metaprogramming www.mentor.com
New example – computing log2(x) for x=𝟐𝑵
16 Metaprogramming www.mentor.com
New example – computing log2(x) for x=𝟐𝑵
17 Metaprogramming www.mentor.com
You would not do this to your program, why
do it to your compiler?
18 Metaprogramming www.mentor.com
You would not do this to your program, why
do it to your compiler?
19 Metaprogramming www.mentor.com
One caveat
If-then-else:
template <bool N, typename T, typename F> struct IF {
typedef T type;
};
template <typename T, typename F> struct IF<false,T,F> {
typedef F type;
};
C++11 has this very construct as std::conditional
21 Metaprogramming www.mentor.com
Tools of metaprogramming
22 Metaprogramming www.mentor.com
Compile-time (static) assertions
23 Metaprogramming www.mentor.com
Guidelines for using metaprogramming in
everyday application programming
Compile-time numeric calculations
— Also consider constexpr functions in C++11
— Use precomputed static values when it’s simpler (𝜋)
24 Metaprogramming www.mentor.com
Types of metaprograms
25 Metaprogramming www.mentor.com
Example – computing 𝒙𝑵
27 Metaprogramming www.mentor.com
Example – computing 𝒙𝑵 (for all N)
For even N we need:
return Pow<N/2>()(x)*Pow<N/2>()(x);
For odd N we need:
return x*Pow<(N-1)/2>()(x)*Pow<N/2>()(x);
For N=0 we need: return 1
template <size_t N> struct Pow {
double operator()(double x) const {
return (N%2) ? x*Pow<N/2>()(x)*Pow<N/2>()(x)
Pow<N/2>
Pow<N/2>
: (N ? Pow<N/2>()(x)*Pow<N/2>()(x))
: 1 ); } };
Both expressions in ?: must be valid, even if only one is
used to compute result (cannot hide compiler errors in ?:)
— Same for &&/|| short-circuiting
28 Metaprogramming www.mentor.com
Example – computing 𝒙𝑵 with partial
specializations
30 Metaprogramming www.mentor.com
More practical metaprogramming examples
31 Metaprogramming www.mentor.com
Guidelines for using metaprogramming in
everyday application programming
Compile-time numeric calculations
— Also consider constexpr functions in C++11
— Use precomputed static values when it’s simpler (𝜋)
Code generation using numeric calculations
— Less computation at run time == good
32 Metaprogramming www.mentor.com
Types of metaprograms
33 Metaprogramming www.mentor.com
Example – bit string
34 Metaprogramming www.mentor.com
Indexing bits
word index 0 1
bit index 31 0 31 0
63 54 0
bit_index = index & 0x1F; word_index = index >> 5;
35 Metaprogramming www.mentor.com
Indexing bits in a template
36 Metaprogramming www.mentor.com
Example - deque
37 Metaprogramming www.mentor.com
Example – deque<int>
block (T[N])
N = BlockSize/sizeof(T)
39 Metaprogramming www.mentor.com
Indexing deque<T>
40 Metaprogramming www.mentor.com
Guidelines for using metaprogramming in
everyday application programming
Compile-time numeric calculations
— Also consider constexpr functions in C++11
— Use precomputed static values when it’s simpler (𝜋)
Code generation using numeric calculations
— Less computation at run time == good
“Self-adapting” code
— Automatic portability
41 Metaprogramming www.mentor.com
Types of metaprograms
42 Metaprogramming www.mentor.com
Type manipulations
44 Metaprogramming www.mentor.com
Type manipulations
47 Metaprogramming www.mentor.com
Life before C++11 was miserable…
48 Metaprogramming www.mentor.com
With C++11 you have it all…
49 Metaprogramming www.mentor.com
Guidelines for using metaprogramming in
everyday application programming
Compile-time numeric calculations
— Also consider constexpr functions in C++11
— Use precomputed static values when it’s simpler (𝜋)
Code generation using numeric calculations
— Less computation at run time == good
“Self-adapting” code
— Automatic portability
Type manipulations
— In C++11, use std:: metafunctions (in C++03, know C++11
additions, follow the interface, you can implement most of them)
50 Metaprogramming www.mentor.com
Types of metaprograms
51 Metaprogramming www.mentor.com
Type-dependent code
52 Metaprogramming www.mentor.com
Example – container with internal sort
53 Metaprogramming www.mentor.com
Example – container with internal sort
54 Metaprogramming www.mentor.com
Example – container with internal sort
57 Metaprogramming www.mentor.com
How to test for something that may not be
there?
58 Metaprogramming www.mentor.com
SFINAE – where compiler errors go to hide
59 Metaprogramming www.mentor.com
SFINAE check for a member function
60 Metaprogramming www.mentor.com
Argument non-evaluation
61 Metaprogramming www.mentor.com
SFINAE check for a member function
62 Metaprogramming www.mentor.com
SFINAE before C++11
63 Metaprogramming www.mentor.com
Example – use T::sort() when available
65 Metaprogramming www.mentor.com
Even farther back
68 Metaprogramming www.mentor.com
Valid expression test in C++03
(“if_compiles”)
DEFINE_IF_COMPILES1(AddInt, x1+1);
DEFINE_IF_COMPILES1(DefaultCtor, new T1);
DEFINE_IF_COMPILES1(AssignInt, x1=1);
DEFINE_IF_COMPILES1(HasSort, x1.sort());
DEFINE_IF_COMPILES1(HasSortInt, x1.sort(1));
DEFINE_IF_COMPILES1(HasAnySort, &T1::sort);
Checks for expressions with 2, 3, … different types are
similarly defined (naming: T1, x1, T2, x2, …)
DEFINE_IF_COMPILES2(Add, x1+x2);
DEFINE_IF_COMPILES2(ConvertFrom, T1(x2));
DEFINE_IF_COMPILES2(Assign, x1=x2);
DEFINE_IF_COMPILES3(MyExpr, x1+x2*x3/2);
STATIC_ASSERT(MyExpr<int, MyFrac, double>::value);
72 Metaprogramming www.mentor.com
Valid expression test in C++11
Practical/Applications Advanced/Libraries
Compile-time numeric calculations
Code generation using numeric calculations
“Self-adapting” code
Type manipulations
Type-dependent code
Precise type processing
Typelists and other “type collections”
Code generation driven by type collections, e.g. “virtual
template functions”
Domain languages and tools
74 Metaprogramming www.mentor.com
Guidelines for using metaprogramming in
everyday application programming
Compile-time numeric calculations
— Also consider constexpr functions in C++11
— Use precomputed static values when it’s simpler (𝜋)
Code generation using numeric calculations
— Less computation at run time == good
“Self-adapting” code
— Automatic portability
Type manipulations
— In C++11, use std:: metafunctions (in C++03, know C++11
additions, follow the interface, you can implement most of them)
Type-dependent code
— Use type analysis metafunctions and partial specialization when
solution depends on a specific type property
— Use SFINAE (“if_compiles”) when solution depends on supported
operations
75 Metaprogramming www.mentor.com
www.mentor.com