Professional Documents
Culture Documents
Variable Templates and
slides: http://wiki.hsr.ch/PeterSommerlad/
void testFactorialCompiletime() {
ASSERT_EQUAL(sizeof(a),sizeof(int)*2*3*4*5);
}
© Peter Sommerlad 4
C++03 Compile-time Computation
• can compute with floating point values at compile time, but only
single statement in constexpr func
© Peter Sommerlad 9
Advertisement
#define ABS(x) (((x)<0)?-(x):(x))
int main() {
cout << "ABS(-1) = "<< ABS(-1) << '\n';
cout << "ABS(MININT) = "<< ABS(numeric_limits<int>::min()) << '\n';
}
int main() {
cout << "ABS(-1) = "<< ABS(-1) << '\n';
cout << "ABS(MININT) = "<< ABS(numeric_limits<int>::min()) << '\n';
}
© Peter Sommerlad 10
Reminder: functions, templates, patterns
© Peter Sommerlad 12
C++11 standard mistake: literal types
© Peter Sommerlad 13
User-defined Literals vs Literal Types
struct velocity {
explicit constexpr velocity(double initial):v{initial}{}
constexpr velocity& operator+=(velocity vdelta){ v+=vdelta.v; return *this;}
friend std::ostream&operator<<(std::ostream &out,velocity const &v){
return out << v.v << " m/s ";
}
constexpr bool operator==(velocity const &other) const{return v == other.v;} // bad impl.
private:
double v;
};
© Peter Sommerlad 14
C++14 Features
variable templates
relaxed constexpr
integer_sequence
Compile-time C++03 computation
template <size_t n> recursion
struct fact{
static size_t const value{(n>1)? n * fact<n-1>::value : 1};
};
template <>
struct fact<0>{
static size_t const value=1; base case
};
specialization
© Peter Sommerlad 17
Variable Templates
template<typename T>
constexpr T pi = T(3.1415926535897932384626433L);
© Peter Sommerlad 19
C++14 Compile-time Computation
constexpr auto factorial(unsigned n){
unsigned long long res{1};
while(n>1) res*=n--; side-effects on locals only
return res;
} constant expression context
static_assert(fac<20> ==factorial(20),"loop version incorrect");
© Peter Sommerlad 20
C++14 constexpr compile times…
http://xkcd.com/303/
© Peter Sommerlad 21
C++14 can deduce return type
template <typename T>
constexpr auto abs(T x){ return x<0?-x:x;}
static_assert(5==abs(-5),"abs is correct for negative int");
static_assert(5==abs(5),"abs is correct for int");
static_assert(5.0==abs(-5.0),"abs is correct for negative double");
static_assert(5.0l==abs(-5.0l),"abs is correct for negative long double");
© Peter Sommerlad 22
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
2 4 6 8 10 12 14 16 18 20 22 24 26 28 30 32 34 36 38 40
3 6 9 12 15 18 21 24 27 30 33 36 39 42 45 48 51 54 57 60
4 8 12 16 20 24 28 32 36 40 44 48 52 56 60 64 68 72 76 80
5 10 15 20 25 30 35 40 45 50 55 60 65 70 75 80 85 90 95 100
6 12 18 24 30 36 42 48 54 60 66 72 78 84 90 96 102 108 114 120
7 14 21 28 35 42 49 56 63 70 77 84 91 98 105 112 119 126 133 140
8 16 24 32 40 48 56 64 72 80 88 96 104 112 120 128 136 144 152 160
9 18 27 36 45 54 63 72 81 90 99 108 117 126 135 144 153 162 171 180
10 20 30 40 50 60 70 80 90 100 110 120 130 140 150 160 170 180 190 200
11 22 33 44 55 66 77 88 99 110 121 132 143 154 165 176 187 198 209 220
12 24 36 48 60 72 84 96 108 120 132 144 156 168 180 192 204 216 228 240
13 26 39 52 65 78 91 104 117 130 143 156 169 182 195 208 221 234 247 260
14 28 42 56 70 84 98 112 126 140 154 168 182 196 210 224 238 252 266 280
15 30 45 60 75 90 105 120 135 150 165 180 195 210 225 240 255 270 285 300
16 32 48 64 80 96 112 128 144 160 176 192 208 224 240 256 272 288 304 320
17 34 51 68 85 102 119 136 153 170 187 204 221 238 255 272 289 306 323 340
18 36 54 72 90 108 126 144 162 180 198 216 234 252 270 288 306 324 342 360
19 38 57 76 95 114 133 152 171 190 209 228 247 266 285 304 323 342 361 380
20 40 60 80 100 120 140 160 180 200 220 240 260 280 300 320 340 360 380 400
© Peter Sommerlad 23
Literal Types and constexpr
template <typename T, size_t n>
struct ar{ replacement for std::array as literal
constexpr ar():a{{}}{} type mutable at compile time
constexpr T const & operator[](size_t i) const { return a[i];}
constexpr T & operator[](size_t i) { return a[i];}
private:
T a[n]; non-const constexpr!
};
© Peter Sommerlad 24
std::array<T,N> in C++14 incomplete
template <typename T, size_t n>
struct ar{
constexpr ar():a{{}}{}
constexpr T const & operator[](size_t i) const { return a[i];}
constexpr T & operator[](size_t i) { return a[i];}
private:
T a[n]; non-constexpr in std::array
};
© Peter Sommerlad 25
Limitation: Parameters
template <size_t n>
using arr=ar<size_t,n>;
© Peter Sommerlad 26
integer_sequence/index_sequence
template <typename T, T...vals>
constexpr auto
make_init_array(std::integer_sequence<T,vals...>){
return std::array<T,sizeof...(vals)>{{vals...}};
}
• make_index_sequence<n>{}: <size_t,0,1,2,…,n-1>
© Peter Sommerlad 27
compile-time sequence handling
template <char... s>
using char_sequence=std::integer_sequence<char,s...>; template alias
template <char ...s>
constexpr auto newline(char_sequence<s...>){ append line feed
return char_sequence<s...,'\n'>{};
}
constexpr auto newline(){ produce a sequence only with line feed
return char_sequence<'\n'>{};
}
template <typename INT, INT ...s, INT ...t> combine sequences s and t
constexpr auto
concat_sequence(std::integer_sequence<INT,s...>,std::integer_sequence<INT,t...>){
return std::integer_sequence<INT,s...,t...>{};
}
© Peter Sommerlad 28
Converting numbers to CTS
constexpr char make_digit_char(size_t const digit,
size_t const power_of_ten=1,char const zero=' '){
return char(digit>=power_of_ten?digit/power_of_ten+'0':zero);
}
• can create new sequence type with changed values, like with
concatenation
• 0,1,2,3,…num-1 — make_index_sequence
• 1,2,3,4,…num — add<1>
• 3,6,9,12,…3*num — multiply<row> with row=3
• makerowcharseq will transform this to chars
© Peter Sommerlad 31
character_sequence from a row
template <size_t n, size_t ...rest>
constexpr auto convert_to_charseq(){
return concat_sequence(
recurse indirectly
through class template
make_chars_from_num<n>(),
convert_to_charseq_impl<rest...>{}());
}
template<size_t ...rows>
constexpr auto makerowcharseq(std::index_sequence<rows...>){
return newline(convert_to_charseq<rows...>());
}
• Forward declaration
template <size_t n, size_t ...rest>
constexpr auto convert_to_charseq(){
return concat_sequence(
make_chars_from_num<n>(),
needed
convert_to_charseq_impl<rest...>{}());
}
template <size_t...elts> • call operator for syntax
struct convert_to_charseq_impl{ convenience (not required),
constexpr auto operator()()const {
return convert_to_charseq<elts...>(); other member can do
}
};
template <>
• recurse to function
struct convert_to_charseq_impl<>{
constexpr auto operator()()const{ • base case: empty
return char_sequence<>{}; sequence
}
};
© Peter Sommerlad 33
generating all rows
template <size_t n,size_t...rows>
forward declaration for recursion
struct make_rows_as_charseq_impl;
• recurse to function
• base case: empty result
© Peter Sommerlad 35
putting table together…
template <size_t n,size_t ...rows>
constexpr auto makerows(std::index_sequence<rows...>){
return make_rows_as_charseq<n,rows...>();
}
template <size_t dim>
constexpr auto multiplication_table=
make_char_string_from_sequence(
concat_sequence(newline(),
makerows<dim>(
add<1>(
std::make_index_sequence<dim>{}))));
© Peter Sommerlad 36
std::string const expected=R"(
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
2 4 6 8 10 12 14 16 18 20 22 24 26 28 30 32 34 36 38 40
3 6 9 12 15 18 21 24 27 30 33 36 39 42 45 48 51 54 57 60
4 8 12 16 20 24 28 32 36 40 44 48 52 56 60 64 68 72 76 80
5 10 15 20 25 30 35 40 45 50 55 60 65 70 75 80 85 90 95 100
6 12 18 24 30 36 42 48 54 60 66 72 78 84 90 96 102 108 114 120
7 14 21 28 35 42 49 56 63 70 77 84 91 98 105 112 119 126 133 140
8 16 24 32 40 48 56 64 72 80 88 96 104 112 120 128 136 144 152 160
9 18 27 36 45 54 63 72 81 90 99 108 117 126 135 144 153 162 171 180
10 20 30 40 50 60 70 80 90 100 110 120 130 140 150 160 170 180 190 200
11 22 33 44 55 66 77 88 99 110 121 132 143 154 165 176 187 198 209 220
12 24 36 48 60 72 84 96 108 120 132 144 156 168 180 192 204 216 228 240
13 26 39 52 65 78 91 104 117 130 143 156 169 182 195 208 221 234 247 260
14 28 42 56 70 84 98 112 126 140 154 168 182 196 210 224 238 252 266 280
15 30 45 60 75 90 105 120 135 150 165 180 195 210 225 240 255 270 285 300
16 32 48 64 80 96 112 128 144 160 176 192 208 224 240 256 272 288 304 320
17 34 51 68 85 102 119 136 153 170 187 204 221 238 255 272 289 306 323 340
18 36 54 72 90 108 126 144 162 180 198 216 234 252 270 288 306 324 342 360
19 38 57 76 95 114 133 152 171 190 209 228 247 266 285 304 323 342 361 380
20 40 60 80 100 120 140 160 180 200 220 240 260 280 300 320 340 360 380 400
)”;
ASSERT_EQUAL(expected,multiplication_table<20>);
© Peter Sommerlad 37
A table with sine values for a circle
constexpr auto largesinustab=tables::make_sinus_table<360+1,double>;
// limited to 1 degree -fconstexpr-steps=larger to get more
static_assert(largesinustab.front()==0,"sin 0 is 0");
static_assert(abs(largesinustab.back())<1e-12,"sin 2 pi is 0");
static_assert(abs(largesinustab[90]-1)<1e-10,"sine 90 degree is 1");
static_assert(abs(largesinustab[180])<1e-10,"sine 180 degree is 0");
static_assert(abs(largesinustab[270]+1)<1e-10,"sine 270 is 1");
© Peter Sommerlad 38
constructing the table
template <typename T, size_t ...indices>
constexpr auto
make_sinus_table_impl(std::index_sequence<indices...>){
sizeof…
static_assert(sizeof...(indices)>1,
"must have 2 values to interpolate");
return std::array<T,sizeof...(indices)>{{
pack expansion:
sin(indices*two_pi<T>/(sizeof...(indices)-1))... expression for each value
}}; in parameter pack
}
template <size_t n, typename T=long double>
constexpr auto make_sinus_table=
0,1,2,3,…n-1
make_sinus_table_impl<T>(std::make_index_sequence<n>{});
© Peter Sommerlad 40
Dealing with ∏
template<typename T>
constexpr T pi = T(3.1415926535897932384626433L);
template<typename T>
constexpr T two_pi =2.0L*pi<T>;
© Peter Sommerlad 41
using degrees for constants
template <short deg, short minutes=0, short seconds=0>
constexpr long double
degrees{(deg+minutes/60.0l+seconds/3600.0l)*pi<long double>/180.0l};
static_assert(pi<long double>/2 == degrees<90>,"90 degrees are pi half");
• using it:
constexpr auto sinus30degrees = sin(degrees<30>);
constexpr auto bristolNorth=tailor::degrees<51,27>;
constexpr auto bristolWest=tailor::degrees<2,35>;
© Peter Sommerlad 42
Wrap up
• contact: peter.sommerlad@hsr.ch
• Looking for a better IDE: