├── .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 | [![Build Status](https://travis-ci.org/elliotgoodrich/VariadicTemplateAlgorithms.svg?branch=master)](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(f), 322 | std::forward(fixed), 323 | std::forward(rest)..., 324 | std::forward(first)); 325 | } 326 | }; 327 | 328 | template <> 329 | struct left_shift_tail<0u> { 330 | template 331 | constexpr static auto transform(Function&& f, Args&&... rest) { 332 | return id::transform(std::forward(f), std::forward(rest)...); 333 | } 334 | }; 335 | 336 | /** Right cyclic shifts the tail of the parameters \a n places. */ 337 | template 338 | struct right_shift_tail { 339 | template 340 | constexpr static auto transform(Function&& f, Args&&... args) { 341 | static_assert(N < sizeof...(args) - 1, 342 | "Cannot right shift more than the size of the tail of the parameter pack"); 343 | return left_shift_tail::transform(std::forward(f), 344 | std::forward(args)...); 345 | } 346 | }; 347 | 348 | template <> 349 | struct right_shift_tail<0u> { 350 | template 351 | constexpr static auto transform(Function&& f, Args&&... rest) { 352 | return id::transform(std::forward(f), std::forward(rest)...); 353 | } 354 | }; 355 | 356 | template = 0)> 357 | struct shift_tail; 358 | 359 | template 360 | struct shift_tail { 361 | template 362 | constexpr static auto transform(Function&& f, Args&&... args) { 363 | return left_shift_tail::transform(std::forward(f), 364 | std::forward(args)...); 365 | } 366 | }; 367 | 368 | template 369 | struct shift_tail { 370 | template 371 | constexpr static auto transform(Function&& f, Args&&... args) { 372 | return right_shift_tail<-N>::transform(std::forward(f), 373 | std::forward(args)...); 374 | } 375 | }; 376 | 377 | namespace detail { 378 | 379 | template 380 | struct drop_helper { 381 | template 382 | constexpr static auto transform(Function&& f, First&&, Args&&... args) { 383 | return drop_helper::transform(std::forward(f), std::forward(args)...); 384 | } 385 | }; 386 | 387 | template <> 388 | struct drop_helper<0u> { 389 | template 390 | constexpr static auto transform(Function&& f, Args&&... args) { 391 | return id::transform(std::forward(f), std::forward(args)...); 392 | } 393 | }; 394 | 395 | } 396 | 397 | /** Drops the first N arguments. */ 398 | template 399 | struct drop { 400 | template 401 | constexpr static auto transform(Function&& f, Args&&... args) { 402 | static_assert(-count(args...) <= N && N <= count(args...), 403 | "Cannot drop more variables than are passed"); 404 | return detail::drop_helper::transform(std::forward(f), std::forward(args)...); 405 | } 406 | }; 407 | 408 | namespace detail { 409 | 410 | template 411 | struct take_helper; 412 | 413 | template 414 | struct take_helper { 415 | template 416 | constexpr static auto transform(Function&& f, Args&&... args) { 417 | return id::transform(std::forward(f), std::forward(args)...); 418 | } 419 | }; 420 | 421 | template 422 | struct take_helper { 423 | template 424 | constexpr static auto transform(Function&& f, Args&&... args) { 425 | return compose, 426 | drop 427 | >::transform(std::forward(f), std::forward(args)...); 428 | } 429 | }; 430 | 431 | } 432 | 433 | /** Passes only the first N arguments. */ 434 | template 435 | struct take { 436 | template 437 | constexpr static auto transform(Function&& f, Args&&... args) { 438 | static_assert(-count(args...) <= N && N <= count(args...), "Cannot take more parameters that are available"); 439 | return detail::take_helper::transform(std::forward(f), 441 | std::forward(args)...); 442 | } 443 | }; 444 | 445 | template <> 446 | struct take<0u> { 447 | template 448 | constexpr static auto transform(Function&& f, Args&&...) { 449 | return std::forward(f)(); 450 | } 451 | }; 452 | 453 | /** Take only the arguments at positions N, N + 1, ..., M - 1, M */ 454 | template 455 | struct slice { 456 | template 457 | constexpr static auto transform(Function&& f, Args&&... args) { 458 | static_assert(-count(args...) <= N && N < count(args...), 459 | "N is out of bounds"); 460 | static_assert(-count(args...) <= M && M < count(args...), 461 | "M is out of bounds"); 462 | static int const A = (N + count(args...)) % count(args...); 463 | static int const B = (M + count(args...)) % count(args...); 464 | static_assert(A <= B, "N must be <= M"); 465 | static_assert(B <= count(args...), "M is out of bounds"); 466 | return m_slice::transform(std::forward(f), std::forward(args)...); 467 | } 468 | 469 | private: 470 | template 471 | struct m_slice { 472 | template 473 | constexpr static auto transform(Function&& f, Args&&... args) { 474 | return compose, 475 | drop 476 | >::transform(std::forward(f), std::forward(args)...); 477 | } 478 | }; 479 | }; 480 | 481 | /** Swap the parameters in the positions \a n and \a m. If a number is negative, it is counted from 482 | the end of the parameter pack. e.g. -1 would be the last parameter. */ 483 | template 484 | struct swap { 485 | template 486 | constexpr static auto transform(Function&& f, Args&&... args) { 487 | static int const size = count(args...); 488 | static_assert(-size <= N && N < size, 489 | "N is out of bounds"); 490 | static_assert(-size <= M && M < size, 491 | "M is out of bounds"); 492 | static int const A = (N + size) % size; 493 | static int const B = (M + size) % size; 494 | static int const min = A < B ? A : B; 495 | static int const max = A < B ? B : A; 496 | return swap_helper::transform(std::forward(f), std::forward(args)...); 497 | } 498 | 499 | private: 500 | template 501 | struct swap_helper { 502 | template 503 | constexpr static auto transform(Function&& f, Args&&... args) { 504 | return compose, 505 | shift_tail, 506 | flip, 507 | shift_tail<-(Max - Min - 1)>, 508 | shift<-Min> 509 | >::transform(std::forward(f), std::forward(args)...); 510 | } 511 | }; 512 | 513 | template 514 | struct swap_helper { 515 | template 516 | constexpr static auto transform(Function&& f, Args&&... args) { 517 | return id::transform(std::forward(f), std::forward(args)...); 518 | } 519 | }; 520 | }; 521 | 522 | namespace detail { 523 | 524 | template 525 | struct modulus { 526 | static int const value = (N + Modulus) % Modulus; 527 | }; 528 | 529 | } 530 | 531 | template 532 | struct cycle; 533 | 534 | template <> 535 | struct cycle<> { 536 | template 537 | constexpr static auto transform(Function&& f, Args&&... args) { 538 | return id::transform(std::forward(f), std::forward(args)...); 539 | } 540 | }; 541 | 542 | template 543 | struct cycle { 544 | template 545 | constexpr static auto transform(Function&& f, Args&&... args) { 546 | return id::transform(std::forward(f), std::forward(args)...); 547 | } 548 | }; 549 | 550 | template 551 | struct cycle { 552 | template 553 | constexpr static auto transform(Function&& f, Args&&... args) { 554 | static_assert(vta::are_unique_ints::value, 555 | detail::modulus::value, 556 | detail::modulus::value...>::value, 557 | "The positions to permute must be unique"); 558 | return compose, cycle>::transform(std::forward(f), std::forward(args)...); 559 | } 560 | }; 561 | 562 | namespace detail { 563 | 564 | template 565 | struct reverse_helper { 566 | template 567 | constexpr static auto transform(Function&&) { 568 | } 569 | 570 | template 571 | constexpr static auto transform(Function&& f, Arg&& arg) { 572 | return id::transform(std::forward(f), std::forward(arg)); 573 | } 574 | 575 | template 576 | constexpr static auto transform(Function&& f, First&& first, Args&&... args) { 577 | return compose, 578 | reverse_helper 579 | >::transform(std::forward(f), 580 | std::forward(first), 581 | std::forward(args)...); 582 | } 583 | }; 584 | 585 | template <> 586 | struct reverse_helper<0u> { 587 | template 588 | constexpr static auto transform(Function&& f, Args&&... args) { 589 | return id::transform(std::forward(f), std::forward(args)...); 590 | } 591 | }; 592 | 593 | } 594 | 595 | /** Reverse the order of arguments */ 596 | struct reverse { 597 | template 598 | constexpr static auto transform(Function&& f, Args&&... args) { 599 | return detail::reverse_helper::transform(std::forward(f), 600 | std::forward(args)...); 601 | } 602 | }; 603 | 604 | namespace detail { 605 | 606 | template