├── .travis.yml
├── API_REFERENCE.md
├── CMakeLists.txt
├── LICENSE.md
├── README.md
├── examples
├── CMakeLists.txt
├── concat.cpp
├── reverse_polish.cpp
├── safe_mean.cpp
└── switch_bools.cpp
├── include
├── CMakeLists.txt
└── vta
│ └── algorithms.hpp
└── tests
├── CMakeLists.txt
├── algorithms.cpp
└── main.cpp
/.travis.yml:
--------------------------------------------------------------------------------
1 | language:
2 | - cpp
3 |
4 | compiler:
5 | - gcc
6 |
7 | before_install:
8 | - sudo add-apt-repository ppa:ubuntu-toolchain-r/test -y
9 | - sudo add-apt-repository -y ppa:boost-latest/ppa
10 | - sudo apt-get update -qq
11 | - sudo apt-get install -qq libboost1.55-all-dev
12 | - if [ "$CXX" = "clang++" ]; then sudo apt-get install -qq libstdc++-4.9-dev; fi
13 | - if [ "$CXX" = "g++" ]; then sudo apt-get install -qq g++-4.9; fi
14 | - if [ "$CXX" = "g++" ]; then export CXX="g++-4.9" CC="gcc-4.9"; fi
15 |
16 | script:
17 | - mkdir build
18 | - cd build
19 | - cmake ..
20 | - make -j5
21 | - ctest --output-on-failure
22 |
--------------------------------------------------------------------------------
/API_REFERENCE.md:
--------------------------------------------------------------------------------
1 | VTA API Reference
2 | =================
3 |
4 | * [Predicates](#predicate)
5 | * [Miscellaneous Functions](#misc)
6 | * [Type aliases](#alias)
7 | * [Variadic Functors](#functor)
8 | * [Tranformations](#transformation)
9 | * [Macros](#macro)
10 |
11 | Predicates
12 | ----------
13 |
14 | VTA contains similar tools to those found in `` to decide whether one or more types have a certain property.
15 |
16 | ---
17 | #### `are_same`
18 | ```cpp
19 | template
20 | struct are_same {
21 | static bool const value;
22 | };
23 | ```
24 |
25 | This struct is an extension of `std::is_same` that operates on multiple types. `value` is `true` only if all of the types `Args...` are the same, `false` otherwise. If there are 0 or 1 types, then `value` is always `true`.
26 |
27 | ##### example
28 | ```cpp
29 | static_assert(vta::are_same::value, "");
30 | static_assert(!vta::are_same::value, "");
31 | ```
32 |
33 | ---
34 | #### `are_same_after`
35 | ```cpp
36 | template
37 | struct are_same_after {
38 | static bool const value
39 | = vta::are_same::type...>::value;
40 | };
41 | ```
42 |
43 | This struct is a shorthand way to apply a type transformation to all of `Args...` and the variable `value` is the result of whether these are all the same type or not.
44 |
45 | ##### example
46 | ```cpp
47 | static_assert(vta::are_same_after::value, "");
48 | ```
49 |
50 | ---
51 | #### `are_unique`
52 | ```cpp
53 | template
54 | struct are_unique{
55 | static bool const value;
56 | };
57 | ```
58 |
59 | `value` is true if and only if all `Args...` are unique types
60 |
61 | ##### example
62 | ```cpp
63 | static_assert(vta::are_unique::value, "");
64 | static_assert(!vta::are_unique::value, "");
65 | ```
66 |
67 | ---
68 | #### `are_unique_after`
69 | ```cpp
70 | template
71 | struct are_unique_after{
72 | static bool const value
73 | = vta::are_unique::type...>::value;
74 | };
75 | ```
76 |
77 | This struct is a shorthand way to apply a type transformation to all of `Args...` and the variable `value` is the result of whether all of these are unique.
78 |
79 | ##### example
80 | ```cpp
81 | static_assert(!vta::are_unique_after::value, "");
82 | ```
83 |
84 | ---
85 | #### `are_unique_ints`
86 | ```cpp
87 | template
88 | struct are_unique_ints {
89 | static bool const value;
90 | };
91 | ```
92 |
93 | `value` is true if no `int` that appears in `Ns...` appears more than once.
94 |
95 | ##### examples
96 | ```cpp
97 | static_assert(vta::are_unique_ints<1, 2, 3>::value, "");
98 | static_assert(!vta::are_unique_ints<1, 2, 3, 2>::value, "");
99 | ```
100 |
101 | Miscellaneous Functions
102 | ---------
103 | Some of the signatures of functions and classes are not 100% correct C++, but they are written this way for clarity (for example `vta::last` and `vta::at`).
104 |
105 | ---
106 | #### `head`
107 | ```cpp
108 | template
109 | constexpr Head&& head(Head&&, Args&&...) noexcept;
110 | ```
111 |
112 | Returns a reference to the first argument with the same value category it had when it was passed in to `head`.
113 |
114 | ##### examples
115 | ```cpp
116 | std::string s = vta::head("hello", 1, '2'); // s = "hello"
117 | std::string t = vta::head(std::move(s), "world"); // s is moved into t
118 | ```
119 |
120 | ---
121 | #### `last`
122 | ```cpp
123 | template
124 | constexpr Last&& head(Args&&..., Last&&) noexcept;
125 | ```
126 |
127 | Returns a reference to the last argument with the same value category it had when it was passed in to `last`.
128 |
129 | ##### examples
130 | ```cpp
131 | int i = vta::last('1', 2); // i = 2
132 | ```
133 |
134 | ---
135 | #### `at`
136 | ```cpp
137 | template
138 | constexpr Arg&& at(Before&&..., Arg&&, After&&...) noexcept;
139 | ```
140 |
141 | Returns a reference to the `N`-th argument with the same value category it had when it was passed in to `at`. Negative values of `N` are allowed and these count backwards from the last argument. e.g. `at<-1>` returns the last parameter and `at<-2>` returns the penultimate parameter.
142 |
143 | ##### examples
144 | ```cpp
145 | int i = vta::at<1>('1', 2, "3"); // i = 2
146 | std::string s = vta::at<-1>('1', 2, "3"); // s = "3"
147 | char c = vta::at<-3>('1', 2, "3"); // c = '1'
148 | ```
149 |
150 | ---
151 | #### `add_const`
152 | ```cpp
153 | template
154 | constexpr T const& add_const(T&&) noexcept;
155 | ```
156 |
157 | When dealing with variadic functors created by this library, the `const` overload of `operator()` is `constexpr` and the non-`const` is not. In `constexpr` functions it is necessary to use the `const` overload, `add_const` is very useful in these situations.
158 |
159 | ##### examples
160 | ```cpp
161 | auto sum = [](auto l, auto r){ return l + r; };
162 |
163 | template
164 | constexpr auto sum(Args... args) {
165 | return vta::add_const(vta::foldl(sum))(0, args...);
166 | }
167 | ```
168 |
169 | Type aliases
170 | ------------
171 |
172 | #### `head_t`
173 | ```cpp
174 | template
175 | using head_t = decltype(head(std::declval()...));
176 | ```
177 |
178 | `head_t` is a type alias for the first type in `Args...`.
179 |
180 | ---
181 | #### `last_t`
182 | ```cpp
183 | template
184 | using last_t = decltype(last(std::declval()...));
185 | ```
186 |
187 | `last_t` is a type alias for the last type in `Args...`.
188 |
189 | ---
190 | #### `at_t`
191 | ```cpp
192 | template
193 | struct at_t {
194 | template
195 | using type = decltype(at(std::declval()...));
196 | };
197 | ```
198 |
199 | `at_t::type` is a type alias for the `N`th type in `Args...`.
200 |
201 | Variadic Functor functions
202 | --------------------------
203 |
204 | The following functions in the Variadic Template Algorithm library create a variadic functor. These functors have an unspecified type, but have the following member function signatures.
205 |
206 | ```cpp
207 | struct /*unspecified*/ {
208 | template
209 | constexpr /*depends*/ operator()(Args&&... args) const;
210 |
211 | template
212 | /*depends*/ operator()(Args&&... args);
213 | };
214 | ```
215 |
216 | The return type of `operator()` differs and will be specified for each function.
217 |
218 | Like the standard library, all functions in VTA may copy functors that are passed to it an unspecified number of times. If you want to have reference semantics for functors, use `std::ref` and `std::cref` in ``. No copies of other parameters passed are ever copied, only references are passed around.
219 |
220 | For example:
221 |
222 | ```cpp
223 | // functor can be copied any number of times, whereas arg1, arg2, ... never
224 | // have copies made and are only ever forwarded
225 | vta::map(functor)(arg1, arg2, arg3, arg4);
226 | ```
227 |
228 | When discussed, the index of parameters always begins at 0.
229 |
230 | More than std::numeric_limits::max() parameters may not be passed to any variadic functor (though this situation is unlikely to ever happen naturally, and I'm sure would struggle to compile regardless).
231 |
232 | The variadic functors created are copyable/movable if the function they are created with is copyable/movable.
233 |
234 | ---
235 | #### `map`
236 | ```cpp
237 | template
238 | constexpr /*VariadicFunctor*/ map(Function&& f);
239 | ```
240 |
241 | `map` returns a functor that, when applied to any number of parameters, applies the function `f` to each parameter in order. This functor always returns `void`.
242 |
243 | ##### examples
244 | ```cpp
245 | auto printer = [](auto const& x){ std::cout << x; };
246 | vta::map(printer)("I can count to", 4, '!'); // prints "I can count to 4!"
247 | ```
248 |
249 | ---
250 | #### `foldl`
251 | ```cpp
252 | template
253 | constexpr /*VariadicFunctor*/ foldl(Function&& f);
254 | ```
255 |
256 | `foldl` returns a variadic functor that performs a left fold across it's parameters. If the parameters `arg1`, `arg2`, ..., `argN` are passed, the functor returns `f(...f(f(arg1, arg2), arg3), ...), argN)`. If one parameter is passed, it is the value returned. This variadic functor does not work with 0 parameters.
257 |
258 | ##### examples
259 | ```cpp
260 | auto append = [](std::string const& s, auto x){
261 | std::stringstream ss;
262 | ss << s << x;
263 | return ss.str();
264 | };
265 |
266 | std::string str = vta::foldl(append)("", 1, ',', 2, " and ", 3);
267 | std::cout << str; // prints "1,2 and 3"
268 | ```
269 |
270 | ---
271 | #### `foldr`
272 | ```cpp
273 | template
274 | constexpr /*VariadicFunctor*/ foldr(Function&& f);
275 | ```
276 |
277 | `foldr` returns a variadic functor that performs a right fold across it's parameters. If the parameters `arg1`, `arg2`, ..., `argM`, `argN` are passed, the functor returns `f(arg1, f(arg2, f(... f(argM, argN)...)`. If one parameter is passed, it is the value returned. This variadic functor does not work with 0 parameters.
278 |
279 | ##### examples
280 | ```cpp
281 | auto subtract = [](auto l, auto r){ return l - r; };
282 |
283 | // prints -2 = (0 - (1 - (2 - 3)))
284 | std::cout << vta::foldr(subtract)(0, 1, 2, 3);
285 | ```
286 |
287 | ---
288 | #### `all_of`
289 | ```cpp
290 | template
291 | constexpr /*VariadicFunctor*/ all_of(Function&& f);
292 | ```
293 |
294 | `all_of` returns a variadic functor that returns `true` if and only if `f(a)` returns `true` (or any type convertible to `true`) for all arguments. `f` is applied to the arguments in order. If `f(b)` returns `false` for some parameter `b`, then `f` is no longer applied to the rest of the arguments.
295 |
296 | ##### examples
297 | ```cpp
298 | struct is_positve_int {
299 | bool operator()(int i) const { return i > 0; }
300 |
301 | template
302 | bool operator()(T const&) const { return false; }
303 | };
304 |
305 | bool x = vta::all_of(is_positive_int{})(1, 2, 3); // x = true
306 | bool y = vta::all_of(is_positive_int{})(-4, 2, "s"); // y = false
307 | bool z = vta::all_of(is_positive_int{})('2', 0); // z = false
308 | ```
309 |
310 | ---
311 | #### `any_of`
312 | ```cpp
313 | template
314 | constexpr /*VariadicFunctor*/ any_of(Function&& f);
315 | ```
316 |
317 | `any_of` returns a variadic functor that returns `true` if and only if `f(a)` returns `true` (or any type convertible to `true`) for any argument `a`. `f` is applied to the arguments in order. If `f(b)` does return `true` for some parameter `b`, then `f` is no longer applied to the rest of the arguments.
318 |
319 | ##### examples
320 | ```cpp
321 | struct is_positve_int; // see definition under all_of documentation
322 |
323 | bool x = vta::any_of(is_positive_int{})(1, 2, 3); // x = true
324 | bool y = vta::any_of(is_positive_int{})(-4, 2, "s"); // y = true
325 | bool z = vta::any_of(is_positive_int{})('2', 0); // z = false
326 | ```
327 |
328 | ---
329 | #### `none_of`
330 | ```cpp
331 | template
332 | constexpr /*VariadicFunctor*/ none_of(Function&& f);
333 | ```
334 |
335 | `any_of` returns a variadic functor that returns `true` if and only if `f(a)` returns `false` (or any type convertible to `false`) for all arguments. `f` is applied to the arguments in order. If `f(b)` returns `true` for some parameter `b`, then `f` is no longer applied to the rest of the arguments.
336 |
337 |
338 | ##### examples
339 | ```cpp
340 | struct is_positve_int; // see definition under all_of documentation
341 |
342 | bool x = vta::any_of(is_positive_int{})(1, 2, 3); // x = false
343 | bool y = vta::any_of(is_positive_int{})(-4, 2, "s"); // y = false
344 | bool z = vta::any_of(is_positive_int{})('2', 0); // z = true
345 | ```
346 |
347 | ---
348 | #### `forward_after`
349 | ```cpp
350 | template
351 | constexpr /*VariadicFunctor*/ forward_after(Function&& f);
352 | ```
353 |
354 | Returns a variadic functor that forwards all of it's arguments to `f` after applying transformation `Transformation`. Documentation of available transformation are below.
355 |
356 | ```cpp
357 | auto minus = [](auto l, auto r){ return l - r; };
358 |
359 | // vta::id performs no transformation
360 | int a = vta::forward_after(minus)(4, 2); // a = 2
361 |
362 | // vta::flip swaps the first two arguments
363 | int b = vta::forward_after(minus)(4, 2); // b = -2
364 |
365 | // prints "4321" as vta::reverse reverses the arguments
366 | auto printer = [](auto const& x){ std::cout << x; };
367 | vta::forward_after(vta::map(printer))(1, 2, '3', "4");
368 | ```
369 |
370 | Transformations
371 | ---------------
372 |
373 | Transformations are types that are passed to `forward_after` in order to permute and filters the parameters before fowarding them on. All transformations must have the following `static` function,
374 |
375 | ```cpp
376 | struct Transformation {
377 | template
378 | static auto tranform(Function&&, Args&&...);
379 | };
380 | ```
381 |
382 | The `tranform` function calls `f` with some or all of `args...` after applying some permutation and/or transformation.
383 |
384 | All transformations in VTA have a `constexpr` `transform` function so are available to use in `constexpr` functions.
385 |
386 | #### `id`
387 | ```cpp
388 | struct id;
389 | ```
390 |
391 | `id` forward all arguments without modification.
392 |
393 | ##### examples
394 | ```cpp
395 | // prints "1234"
396 | auto printer = [](auto const& x){ std::cout << x; };
397 | std::forward_after(vta::map(printer))(1, 2u, '3', "4");
398 | ```
399 |
400 | ---
401 | #### `call_if`
402 | ```cpp
403 | template
404 | struct call_if
405 | ```
406 |
407 | `call_if` calls the function only if `Condition` is `true`, otherwise noop.
408 |
409 | ##### examples
410 | ```cpp
411 | // prints "1234"
412 | auto printer = [](auto const& x){ std::cout << x; };
413 | std::forward_after>(vta::map(printer))(1, 2u, '3', "4");
414 |
415 | // prints nothing
416 | std::forward_after>(vta::map(printer))(1, 2u, '3', "4");
417 | ```
418 |
419 | ---
420 | #### `flip`
421 | ```cpp
422 | struct flip;
423 | ```
424 |
425 | `flip` swaps the first and second parameter.
426 |
427 | ##### examples
428 | ```cpp
429 | // prints "2134"
430 | auto printer = [](auto const& x){ std::cout << x; };
431 | std::forward_after(vta::map(printer))(1, 2u, '3', "4");
432 | ```
433 |
434 | ---
435 | #### `left_shift`
436 | ```cpp
437 | template
438 | struct left_shift;
439 | ```
440 |
441 | `left_shift` cyclic shifts the parameters `N` places to the left. `N` must be between 0 and the number of parameters passed to `forward_after` otherwise it will fail to compile.
442 |
443 | ##### examples
444 | ```cpp
445 | // prints "2341"
446 | auto printer = [](auto const& x){ std::cout << x; };
447 | std::forward_after>(vta::map(printer))(1, 2u, '3', "4");
448 | ```
449 |
450 | ---
451 | #### `right_shift`
452 | ```cpp
453 | template
454 | struct right_shift;
455 | ```
456 |
457 | `right_shift` cyclic shifts the parameters `N` places to the right. `N` must be between 0 and the number of parameters passed to `forward_after` otherwise it will fail to compile.
458 |
459 | ##### examples
460 | ```cpp
461 | // prints "4123"
462 | auto printer = [](auto const& x){ std::cout << x; };
463 | std::forward_after>(vta::map(printer))(1, 2u, '3', "4");
464 | ```
465 |
466 | ---
467 | #### `shift`
468 | ```cpp
469 | template
470 | struct shift;
471 | ```
472 |
473 | If `N` is greater than 0, `shift` is the same as `left_shift`, if `N` is less than 0, it is the same as `right_shift<-N>`. If `N` equals 0, then the arguments are forwarded without permutation.
474 |
475 | ---
476 | #### `left_shift_tail`
477 | ```cpp
478 | template
479 | struct left_shift_tail;
480 | ```
481 |
482 | ##### examples
483 | ```cpp
484 | // prints "1342"
485 | auto printer = [](auto const& x){ std::cout << x; };
486 | std::forward_after>(vta::map(printer))(1, 2u, '3', "4");
487 | ```
488 |
489 | `left_shift_tail` cyclic shifts the all parameters but the first, `N` places to the left. `N` must be between 0 and 1 - the number of parameters passed to `forward_after` otherwise it will fail to compile.
490 |
491 | ---
492 | #### `right_shift_tail`
493 | ```cpp
494 | template
495 | struct right_shift_tail;
496 | ```
497 |
498 | `right_shift_tail` cyclic shifts the all parameters but the first, `N` places to the right. `N` must be between 0 and 1 - the number of parameters passed to `forward_after` otherwise it will fail to compile.
499 |
500 | ##### examples
501 | ```cpp
502 | // prints "1423"
503 | auto printer = [](auto const& x){ std::cout << x; };
504 | std::forward_after>(vta::map(printer))(1, 2u, '3', "4");
505 | ```
506 |
507 | ---
508 | #### `shift_tail`
509 | ```cpp
510 | template
511 | struct shift_tail;
512 | ```
513 |
514 | If `N` is greater than 0, `shift_tail` is the same as `left_shift_tail`, if `N` is less than 0, it is the same as `right_shift_tail<-N>`. If `N` equals 0, then the arguments are forwarded without permutation.
515 |
516 | ---
517 | #### `drop`
518 | ```cpp
519 | template
520 | struct drop;
521 | ```
522 |
523 | If `N` is positive,`drop` forwards all but the first `N` arguments. `N` must be less than the number of parameters passed otherwise it will fail to compile. If `N` is negative, `drop` forwards all but the first `-N` arguments.
524 |
525 | ##### examples
526 | ```cpp
527 | // prints "34"
528 | auto printer = [](auto const& x){ std::cout << x; };
529 | std::forward_after>(vta::map(printer))(1, 2u, '3', "4");
530 |
531 | // prints "234"
532 | std::forward_after>(vta::map(printer))(1, 2u, '3', "4");
533 | ```
534 |
535 | ---
536 | #### `take`
537 | ```cpp
538 | template
539 | struct take;
540 | ```
541 |
542 | If `N` is positive,`take` forwards only the first `N` arguments. `N` must be less than the number of parameters passed otherwise it will fail to compile. If `N` is negative, `take` forwards all but the last `-N` arguments.
543 |
544 | ##### examples
545 | ```cpp
546 | // prints "123"
547 | auto printer = [](auto const& x){ std::cout << x; };
548 | std::forward_after>(vta::map(printer))(1, 2u, '3', "4");
549 |
550 | // prints "1"
551 | std::forward_after>(vta::map(printer))(1, 2u, '3', "4");
552 | ```
553 |
554 | ---
555 | #### `slice`
556 | ```cpp
557 | template
558 | struct slice;
559 | ```
560 |
561 | `slice` forwards the arguments with an index inclusively between `N` and `M`. If `N` is negative (or `M` is negative) it counts backwards from the end of the parameters, e.g. -1 is the index of the last parameter. If `N > M` (after accounting for negative indices) then `slice` will fail to compile.
562 |
563 | ##### examples
564 | ```cpp
565 | // prints "23"
566 | auto printer = [](auto const& x){ std::cout << x; };
567 | std::forward_after>(vta::map(printer))(1, 2u, '3', "4");
568 |
569 | // prints "123"
570 | std::forward_after>(vta::map(printer))(1, 2u, '3', "4");
571 |
572 | // prints ""
573 | std::forward_after>(vta::map(printer))(1, 2u, '3', "4");
574 | ```
575 |
576 | ---
577 | #### `swap`
578 | ```cpp
579 | template
580 | struct swap;
581 | ```
582 |
583 | `swap` exchanges the two parameters at position `N` and `M`. If this position is negative, it is counted backwards from the end of the parameters, e.g. -1 is the index of the last parameter.
584 |
585 | ##### examples
586 | ```cpp
587 | // prints "3214"
588 | auto printer = [](auto const& x){ std::cout << x; };
589 | std::forward_after>(vta::map(printer))(1, 2u, '3', "4");
590 |
591 | // prints "4231"
592 | auto printer = [](auto const& x){ std::cout << x; };
593 | std::forward_after>(vta::map(printer))(1, 2u, '3', "4");
594 | ```
595 |
596 | ---
597 | #### `cycle`
598 | ```cpp
599 | template
600 | struct cycle;
601 | ```
602 |
603 | `cycle` permutes the parameters at the positions `Ns...` using [cycle notation](http://en.wikipedia.org/wiki/Cycle_notation). Remember that indexing starts from 0, rather than starting from 1, which is more commonly used in mathematics literature. If any positions are negative, it is counted backwards from the end of the parameters, e.g. -1 is the index of the last parameter.
604 |
605 | All indexes must be unique. `cycle<0, 1, 1>` will not compile. `cycle<-1, 3>` will not compile if there are 4 arguments passed to `forward_after` since -1 and 3 describe the same index.
606 |
607 | ##### examples
608 | ```cpp
609 | // prints "4213"
610 | auto printer = [](auto const& x){ std::cout << x; };
611 | std::forward_after>(vta::map(printer))(1, 2u, '3', "4");
612 |
613 | // prints "4213"
614 | std::forward_after>(vta::map(printer))(1, 2u, '3', "4");
615 | ```
616 |
617 | ---
618 | #### `reverse`
619 | ```cpp
620 | struct reverse;
621 | ```
622 |
623 | `reverse` reverses the order of the arguments passed.
624 |
625 | ##### examples
626 | ```cpp
627 | // prints "4321"
628 | auto printer = [](auto const& x){ std::cout << x; };
629 | std::forward_after>(vta::map(printer))(1, 2u, '3', "4");
630 | ```
631 |
632 | ---
633 | #### `filter`
634 | ```cpp
635 | template
636 | struct filter;
637 | ```
638 |
639 | `filter` only forwards on a type `Arg` if `Filter::value` is `true`. Most structs in `` are appropriate as a filter. An example filter:
640 |
641 | ```cpp
642 | template
643 | struct ExampleFilter {
644 | static bool const value = std::is_enum::value &&
645 | std::is_class::value;
646 | };
647 | ```
648 |
649 | ##### examples
650 | ```cpp
651 | // prints "123"
652 | auto printer = [](auto const& x){ std::cout << x; };
653 | std::forward_after>(vta::map(printer))(1, 2u, '3', "4");
654 | ```
655 |
656 | ---
657 | #### `compose`
658 | ```cpp
659 | template
660 | struct compose;
661 | ```
662 |
663 | `compose` creates a new transformation that would occur after applying all `Transformations...` in order.
664 |
665 | ##### examples
666 | ```cpp
667 | // prints "2431"
668 | auto printer = [](auto const& x){ std::cout << x; };
669 | std::forward_after, // would be "1342"
671 | vta::reverse // prints "2431"
672 | >(vta::map(printer))(1, 2u, '3', "4");
673 | ```
674 |
675 | Macros
676 | ------
677 |
678 | #### `VTA_FN_TO_FUNCTOR`
679 | ```cpp
680 | #define VTA_FN_TO_FUNCTOR(...) [](auto&&... args) \
681 | -> decltype(auto){ return __VA_ARGS__(std::forward(args)...); }
682 | ```
683 |
684 | `VTA_FN_TO_FUNCTOR` creates a lambda that calls the function that was passed as an argument. This is a workaround for passing templated functions, such as `std::max` that would require specifying the type. This macro has been provided by [Florian Weber](http://florianjw.de/en/passing_overloaded_functions.html).
685 |
686 | ##### examples
687 | ```cpp
688 | template
689 | auto max(Args... args) {
690 | return vta::foldl(VTA_FN_TO_FUNCTOR(std::max))(args...);
691 | }
692 | ```
693 |
--------------------------------------------------------------------------------
/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | cmake_minimum_required (VERSION 2.6)
2 | project(VariadicTemplateAlgorithms)
3 | set(VariadicTemplateAlgorithms_VERSION_MAJOR 0)
4 | set(VariadicTemplateAlgorithms_VERSION_MINOR 1)
5 | enable_testing()
6 | add_subdirectory(examples)
7 | add_subdirectory(include)
8 | add_subdirectory(tests)
9 |
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | Boost Software License - Version 1.0 - August 17th, 2003
2 |
3 | Permission is hereby granted, free of charge, to any person or organization
4 | obtaining a copy of the software and accompanying documentation covered by
5 | this license (the "Software") to use, reproduce, display, distribute,
6 | execute, and transmit the Software, and to prepare derivative works of the
7 | Software, and to permit third-parties to whom the Software is furnished to
8 | do so, all subject to the following:
9 |
10 | The copyright notices in the Software and this entire statement, including
11 | the above license grant, this restriction and the following disclaimer,
12 | must be included in all copies of the Software, in whole or in part, and
13 | all derivative works of the Software, unless such copies or derivative
14 | works are solely in the form of machine-executable object code generated by
15 | a source language processor.
16 |
17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 | FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
20 | SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
21 | FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
22 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23 | DEALINGS IN THE SOFTWARE.
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | Variadic Template Algorithms
2 | ============================
3 |
4 | [](https://travis-ci.org/elliotgoodrich/VariadicTemplateAlgorithms)
5 |
6 | Working with parameter packs in C++ can be difficult. Getting a reference to the last argument of a parameter pack or reversing the order of arguments to a function is much harder than it should be. VTA is a header-only C++14 library to make this easier.
7 |
8 | Grabbing the nth parameter is very simple with `vta::head`, `vta::at`, and `vta::last`:
9 |
10 | ```cpp
11 | auto i = vta::head(1, "hello"s, 3.14, '!'); // i is an int with value 1
12 | auto c = vta::last(1, "hello"s, 3.14, '!'); // l is a char with value '!'
13 | auto s = vta::at<1>(1, "hello"s, 3.14, '!'); // s is a std::string with value "hello"
14 |
15 | // vta::at can take negative values to index backward from the end
16 | auto d = vta::at<-2>(1, "hello"s, 3.14, '!'); // d is a double with value 3.14
17 | ```
18 |
19 | There are many functions which return functors that apply a function across any number of arguments. Writing a max function is simple when you can [fold](http://en.wikipedia.org/wiki/Fold_%28higher-order_function%29) across any number of parameters,
20 |
21 | ```cpp
22 | template
23 | auto max(Args... args) {
24 | // Check that all of the arguments are of the same type
25 | static_assert(vta::are_same::type>::value,
26 | "Arguments to max must have the same type");
27 |
28 | // Create a max lambda that can operate on any type
29 | // (note this line is not needed if the VTA_FN_TO_FUNCTOR macro is used)
30 | auto max = [](auto const& l, auto const& r){ return std::max(l, r); };
31 |
32 | // Perform a left fold across the arguments, returning the maximum
33 | return vta::foldl(max)(args...);
34 | }
35 | ```
36 |
37 | Reversing arguments and forwarding them on is also easy,
38 |
39 | ```cpp
40 | // Prints an argument
41 | auto printer = [](auto const& x){ std::cout << x; };
42 |
43 | // Prints all arguments in order
44 | template
45 | void print(Args... args) {
46 | // vta::map applies a function to each argument in order
47 | vta::map(printer)(args...);
48 | }
49 |
50 | // Prints all arguments in reverse order
51 | template
52 | void reverse_print(Args... args) {
53 | // vta::forward_after forwards the arguments to a function after a transformation
54 | vta::forward_after(vta::map(printer))(args...);
55 | }
56 | ```
57 |
58 | The `vta::forward_after` function can perform many other transformations such as swapping arguments or shifting all arguments to the left. The full list of transformation can be found in the [api reference](API_REFERENCE.md#transformations).
59 |
--------------------------------------------------------------------------------
/examples/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | if(CMAKE_COMPILER_IS_GNUCC)
2 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -pedantic -Wextra -Werror -std=c++1y")
3 | endif()
4 |
5 | if(MINGW)
6 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mwindows")
7 | endif()
8 |
9 | include_directories(../include/)
10 |
11 | add_executable(concat concat.cpp)
12 | add_executable(reverse_polish reverse_polish.cpp)
13 | add_executable(safe_mean safe_mean.cpp)
14 | add_executable(switch_bools switch_bools.cpp)
15 |
--------------------------------------------------------------------------------
/examples/concat.cpp:
--------------------------------------------------------------------------------
1 | #include "vta/algorithms.hpp"
2 |
3 | #include
4 | #include
5 | #include
6 | #include
7 |
8 | std::size_t string_size(std::string const& str) noexcept { return str.size(); }
9 | std::size_t string_size(char const* str) noexcept { return std::strlen(str); }
10 | std::size_t string_size(char) noexcept { return 1; }
11 |
12 | auto const sum = [](auto lhs, auto rhs){ return lhs + rhs; };
13 |
14 | template
15 | std::string concat(Args&&... args) {
16 | std::string str;
17 | str.reserve(vta::foldl(sum)(0ul, string_size(args)...));
18 | vta::map([&str](auto const& append){ str += append; })(args...);
19 | return str;
20 | }
21 |
22 | int main() {
23 | std::string name = "World";
24 | auto const hello_world = concat("Hello ", name, '!');
25 | std::cout << hello_world << std::endl;
26 | }
27 |
--------------------------------------------------------------------------------
/examples/reverse_polish.cpp:
--------------------------------------------------------------------------------
1 | #include "vta/algorithms.hpp"
2 |
3 | #include
4 | #include
5 | #include
6 |
7 | struct start_type {};
8 | static constexpr start_type start{};
9 |
10 | struct add_type {};
11 | static constexpr add_type add{};
12 |
13 | struct minus_type {};
14 | static constexpr minus_type minus{};
15 |
16 | struct mult_type {};
17 | static constexpr mult_type mult{};
18 |
19 | struct div_type {};
20 | static constexpr div_type divide{};
21 |
22 | struct fact_type {};
23 | static constexpr fact_type fact{};
24 |
25 | template ::value>* = nullptr>
26 | struct polish_calculator {
27 | constexpr T operator()(std::pair stack, add_type) noexcept {
28 | return stack.first + stack.second;
29 | }
30 |
31 | constexpr T operator()(std::pair stack, minus_type) noexcept {
32 | return stack.first - stack.second;
33 | }
34 |
35 | constexpr T operator()(std::pair stack, mult_type) noexcept {
36 | return stack.first * stack.second;
37 | }
38 |
39 | constexpr T operator()(std::pair stack, div_type) noexcept {
40 | return stack.first / stack.second;
41 | }
42 |
43 | // Only allow factorial if the type is integral (e.g. disable for double)
44 | // This function can only throw if T is signed, so mark as noexcept otherwise
45 | constexpr auto operator()(T stack, fact_type) noexcept(std::is_unsigned::value)
46 | -> typename std::enable_if::value, T>::type {
47 | return (stack < 0) ? throw std::runtime_error{"Negative value passed to factorial"}
48 | : (stack == 0) ? 1 : stack * (*this)(stack - 1, fact);
49 | }
50 |
51 | constexpr std::pair operator()(T first, T second) noexcept {
52 | return {first, second};
53 | }
54 |
55 | constexpr T operator()(start_type, T second) noexcept {
56 | return second;
57 | }
58 | };
59 |
60 | // This function can only throw if call factorial on a signed value, so mark as nothrow if we
61 | // are operating on an unsigned type or fact_type is not in Args...
62 | template
63 | constexpr T rev_polish_calc(Args... args)
64 | noexcept(std::is_unsigned::value || vta::are_unique::value) {
65 | return vta::add_const(vta::foldl(polish_calculator{}))(start, args...);
66 | }
67 |
68 | int main()
69 | {
70 | std::cout << "2 3 + = " << rev_polish_calc(2, 3, add) << std::endl;
71 | std::cout << "1 4 * = " << rev_polish_calc(1, 4, mult) << std::endl;
72 | std::cout << "5 2 - 7 * = " << rev_polish_calc(5, 2, minus, 5, mult) << std::endl;
73 | std::cout << "15 4 / 1 + = " << rev_polish_calc(15, 4, divide, 1, add) << std::endl;
74 |
75 | static_assert(rev_polish_calc(3, fact, 2, minus, 8, mult, 2, add) == 34,
76 | "3 ! 2 - 8 * 2 + should equal 34");
77 | }
78 |
--------------------------------------------------------------------------------
/examples/safe_mean.cpp:
--------------------------------------------------------------------------------
1 | #include "vta/algorithms.hpp"
2 |
3 | #include
4 | #include
5 | #include
6 |
7 | template
8 | struct running {
9 | T total;
10 | T remainder;
11 | };
12 |
13 | template
14 | constexpr running safe_mean_foldl(running r, T t) noexcept {
15 | return running{(r.total + t / N) + (r.remainder + t % N) / N,
16 | (r.remainder + t % N) % N};
17 | }
18 |
19 | template ::value
23 | && std::is_arithmetic::value>::type* = nullptr>
24 | constexpr Arg safe_mean(Arg arg, Args... args) noexcept {
25 | return vta::add_const(vta::foldl(&safe_mean_foldl))
26 | (running{0, 0}, arg, args...).total;
27 | }
28 |
29 | template
30 | void print_mean(Arg first, Args... args) {
31 | std::cout << "Arithmetic mean of " << first;
32 | vta::map([](auto x){ std::cout << ", " << x; })(args...);
33 | std::cout << " is ";
34 | std::cout << safe_mean(first, args...);
35 | std::cout << std::endl;
36 | }
37 |
38 | template
39 | constexpr T sum(T lhs, T rhs) noexcept {
40 | return lhs + rhs;
41 | }
42 |
43 | template ::value
47 | && std::is_arithmetic::value>::type* = nullptr>
48 | constexpr Arg unsafe_mean(Arg arg, Args... args) noexcept {
49 | return vta::add_const(vta::foldl(&sum))(arg, args...) / N;
50 | }
51 |
52 | int main()
53 | {
54 | print_mean(1);
55 | print_mean(1, 2);
56 | print_mean(-7, -8);
57 | print_mean(1, 2, 3);
58 | print_mean(-1, 15, 2, -3, 0, 0, 2, 3);
59 |
60 | static_assert(safe_mean(1, 2) == 1, "");
61 | static_assert(safe_mean(std::numeric_limits::max(), std::numeric_limits::max() - 2)
62 | == std::numeric_limits::max() - 1, "");
63 |
64 | static_assert(unsafe_mean(1, 2) == 1, "");
65 | // following line may not compile due to integer overflow
66 | //static_assert(unsafe_mean(std::numeric_limits::max(), std::numeric_limits::max() - 2)
67 | //== std::numeric_limits::max() - 1, "");
68 | }
69 |
--------------------------------------------------------------------------------
/examples/switch_bools.cpp:
--------------------------------------------------------------------------------
1 | #include "vta/algorithms.hpp"
2 |
3 | #include
4 | #include
5 | #include
6 | #include
7 |
8 | constexpr int calculate_switch(int a, bool b) noexcept { return 2 * a + b; }
9 |
10 | template
11 | constexpr int switch_bools(Bools... bools) noexcept {
12 | static_assert(sizeof...(bools) < sizeof(int) * CHAR_BIT, "Too many parameters to switch_bools");
13 | static_assert(vta::are_same_after::value, "");
14 | return vta::add_const(vta::foldl(&calculate_switch))(0, bools...);
15 | }
16 |
17 | int main() {
18 | std::random_device rd;
19 | std::mt19937 eng{rd()};
20 | std::uniform_int_distribution<> generate(0, 1);
21 | bool const a = generate(eng);
22 | bool const b = generate(eng);
23 | bool const c = generate(eng);
24 |
25 | switch(switch_bools(a, b, c)) {
26 | case switch_bools(false, false, false): std::cout << "FFF"; break;
27 | case switch_bools(false, false, true): std::cout << "FFT"; break;
28 | case switch_bools(false, true, false): std::cout << "FTF"; break;
29 | case switch_bools(false, true, true): std::cout << "FTT"; break;
30 | case switch_bools(true, false, false): std::cout << "TFF"; break;
31 | case switch_bools(true, false, true): std::cout << "TFT"; break;
32 | case switch_bools(true, true, false): std::cout << "TTF"; break;
33 | case switch_bools(true, true, true): std::cout << "TTT"; break;
34 | }
35 |
36 | std::cout << std::endl;
37 | }
38 |
--------------------------------------------------------------------------------
/include/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | cmake_minimum_required(VERSION 2.6)
2 |
3 | include_directories(.)
4 |
5 | set(SOURCES
6 | vta/algorithms.hpp
7 | )
8 |
9 | add_library(HEADER_ONLY_TARGET STATIC ${SOURCES})
10 | set_target_properties(HEADER_ONLY_TARGET PROPERTIES LINKER_LANGUAGE CXX)
11 |
--------------------------------------------------------------------------------
/include/vta/algorithms.hpp:
--------------------------------------------------------------------------------
1 | /******************************************************************//**
2 | * \file algorithms.hpp
3 | * \author Elliot Goodrich
4 | *
5 | * Boost Software License - Version 1.0 - August 17th, 2003
6 | *
7 | * Permission is hereby granted, free of charge, to any person or organization
8 | * obtaining a copy of the software and accompanying documentation covered by
9 | * this license (the "Software") to use, reproduce, display, distribute,
10 | * execute, and transmit the Software, and to prepare derivative works of the
11 | * Software, and to permit third-parties to whom the Software is furnished to
12 | * do so, all subject to the following:
13 | *
14 | * The copyright notices in the Software and this entire statement, including
15 | * the above license grant, this restriction and the following disclaimer,
16 | * must be included in all copies of the Software, in whole or in part, and
17 | * all derivative works of the Software, unless such copies or derivative
18 | * works are solely in the form of machine-executable object code generated by
19 | * a source language processor.
20 | *
21 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23 | * FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
24 | * SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
25 | * FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
26 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
27 | * DEALINGS IN THE SOFTWARE.
28 | *********************************************************************/
29 |
30 | #ifndef INCLUDE_GUARD_12E75493_BA12_4EF3_B0D8_92747A030D0E
31 | #define INCLUDE_GUARD_12E75493_BA12_4EF3_B0D8_92747A030D0E
32 |
33 | #include
34 | #include
35 |
36 | namespace vta {
37 |
38 | // Returns the size of the parameter pack as an integer
39 | template
40 | constexpr int count(Args&&...) noexcept {
41 | return sizeof...(Args);
42 | }
43 |
44 | /**************************************************************************************************
45 | * Macro *
46 | **************************************************************************************************/
47 |
48 | // Provided by Florian Weber (http://florianjw.de/en/passing_overloaded_functions.html)
49 | #define VTA_FN_TO_FUNCTOR(...) [](auto&&... args) \
50 | -> decltype(auto){ return __VA_ARGS__(std::forward(args)...); }
51 |
52 | /**************************************************************************************************
53 | * Predicates *
54 | **************************************************************************************************/
55 |
56 | /** are_same */
57 | template
58 | struct are_same;
59 |
60 | template
61 | struct are_same {
62 | static bool const value = std::is_same::value
63 | && are_same::value;
64 | };
65 |
66 | template
67 | struct are_same : public std::true_type {};
68 |
69 | template <>
70 | struct are_same<> : public std::true_type {};
71 |
72 | /** are_same_after */
73 | template class TypeTransformation, typename... Args>
74 | struct are_same_after {
75 | static bool const value = vta::are_same::type...>::value;
76 | };
77 |
78 | /** are_unique_ints */
79 | template
80 | struct are_unique_ints;
81 |
82 | template <>
83 | struct are_unique_ints<> {
84 | static bool const value = true;
85 | };
86 |
87 | template
88 | struct are_unique_ints {
89 | static bool const value = true;
90 | };
91 |
92 | template
93 | struct are_unique_ints {
94 | static bool const value = (M != N)
95 | && are_unique_ints::value
96 | && are_unique_ints::value;
97 | };
98 |
99 | /** are_unique */
100 | template
101 | struct are_unique;
102 |
103 | template <>
104 | struct are_unique<> {
105 | static bool const value = true;
106 | };
107 |
108 | template
109 | struct are_unique {
110 | static bool const value = true;
111 | };
112 |
113 | template
114 | struct are_unique {
115 | static bool const value = (!std::is_same::value)
116 | && are_unique::value
117 | && are_unique::value;
118 | };
119 |
120 | /** are_unique_after */
121 | template class TypeTransformation, typename... Args>
122 | struct are_unique_after {
123 | static bool const value = vta::are_unique::type...>::value;
124 | };
125 |
126 | // Forward after
127 | template
128 | class forward_after_f {
129 | Function mF;
130 |
131 | public:
132 | constexpr forward_after_f(Function f)
133 | : mF(std::move(f)) {
134 | }
135 |
136 | template
137 | constexpr auto operator()(Args&&... args) const {
138 | return Transformation::transform(mF, std::forward(args)...);
139 | }
140 |
141 | template
142 | auto operator()(Args&&... args) {
143 | return Transformation::transform(mF, std::forward(args)...);
144 | }
145 | };
146 |
147 | template
148 | constexpr forward_after_f forward_after(Function&& f) {
149 | return {std::forward(f)};
150 | }
151 |
152 | /**************************************************************************************************
153 | * Transformations *
154 | **************************************************************************************************/
155 |
156 | namespace detail {
157 |
158 | template
159 | class compose_helper_f;
160 |
161 | template
162 | class compose_helper_f {
163 | Function mF;
164 |
165 | public:
166 | constexpr compose_helper_f(Function f)
167 | : mF(std::move(f)) {
168 | }
169 |
170 | template
171 | constexpr auto operator()(Args&&... args) const {
172 | return FirstTransform::transform(compose_helper_f{mF},
173 | std::forward(args)...);
174 | }
175 |
176 | template
177 | auto operator()(Args&&... args) {
178 | return FirstTransform::transform(compose_helper_f{mF},
179 | std::forward(args)...);
180 | }
181 | };
182 |
183 | template
184 | class compose_helper_f {
185 | Function mF;
186 |
187 | public:
188 | compose_helper_f(Function f)
189 | : mF(std::move(f)) {
190 | }
191 |
192 | template
193 | constexpr auto operator()(Args&&... args) const {
194 | return mF(std::forward(args)...);
195 | }
196 |
197 | template
198 | auto operator()(Args&&... args) {
199 | return mF(std::forward(args)...);
200 | }
201 | };
202 |
203 | }
204 |
205 | /** Composes a sequence of transformations. */
206 | template
207 | struct compose {
208 | template
209 | constexpr static auto transform(Function&& f, Args&&... args) {
210 | typedef detail::compose_helper_f::type, Transforms...> Helper;
211 | return Helper{f}(std::forward(args)...);
212 | }
213 | };
214 |
215 | /** Forwards the arguments to f without change. */
216 | struct id {
217 | template
218 | constexpr static auto transform(Function&& f, Args&&... args) {
219 | return std::forward(f)(std::forward(args)...);
220 | }
221 | };
222 |
223 | /** Calls the function with the given arguments if Condition is true. */
224 | template
225 | struct call_if;
226 |
227 | template <>
228 | struct call_if {
229 | template
230 | constexpr static auto transform(Function&& f, Args&&... args) {
231 | return id::transform(std::forward(f), std::forward(args)...);
232 | }
233 | };
234 |
235 | template <>
236 | struct call_if {
237 | template
238 | constexpr static void transform(Function&&, Args&&...) noexcept {
239 | }
240 | };
241 |
242 | /** Flips the first two variables. */
243 | struct flip {
244 | template
245 | constexpr static auto transform(Function&& f, First&& first, Second&& second, Args&&... rest) {
246 | return std::forward(f)(std::forward(second),
247 | std::forward(first),
248 | std::forward(rest)...);
249 | }
250 | };
251 |
252 | /** Left cyclic shifts the parameters \a n places. */
253 | template
254 | struct left_shift {
255 | template
256 | constexpr static auto transform(Function&& f, First&& first, Args&&... rest) {
257 | static_assert(N < 1 + sizeof...(rest),
258 | "Cannot left shift more than the size of the parameter pack");
259 | return left_shift::transform(std::forward(f),
260 | std::forward(rest)...,
261 | std::forward(first));
262 | }
263 | };
264 |
265 | template <>
266 | struct left_shift<0u> {
267 | template
268 | constexpr static auto transform(Function&& f, Args&&... rest) {
269 | return id::transform(std::forward(f), std::forward(rest)...);
270 | }
271 | };
272 |
273 | /** Right cyclic shifts the parameters \a n places. */
274 | template
275 | struct right_shift {
276 | template
277 | constexpr static auto transform(Function&& f, Args&&... args) {
278 | static_assert(N < sizeof...(args),
279 | "Cannot right shift more than the size of the parameter pack");
280 | return left_shift::transform(std::forward(f),
281 | std::forward(args)...);
282 | }
283 | };
284 |
285 | template <>
286 | struct right_shift<0u> {
287 | template
288 | constexpr static auto transform(Function&& f, Args&&... rest) {
289 | return id::transform(std::forward(f), std::forward(rest)...);
290 | }
291 | };
292 |
293 | template = 0)>
294 | struct shift;
295 |
296 | template
297 | struct shift {
298 | template
299 | constexpr static auto transform(Function&& f, Args&&... args) {
300 | return left_shift::transform(std::forward(f),
301 | std::forward(args)...);
302 | }
303 | };
304 |
305 | template
306 | struct shift {
307 | template
308 | constexpr static auto transform(Function&& f, Args&&... args) {
309 | return right_shift<-N>::transform(std::forward(f),
310 | std::forward(args)...);
311 | }
312 | };
313 |
314 | /** Left cyclic shifts the tail of the parameters \a n places. */
315 | template
316 | struct left_shift_tail {
317 | template
318 | constexpr static auto transform(Function&& f, Fixed&& fixed, First&& first, Args&&... rest) {
319 | static_assert(N < 1 + sizeof...(rest),
320 | "Cannot left shift more than the size of the tail of the parameter pack");
321 | return left_shift_tail::transform(std::forward