1 /* 2 * Copyright (c) 2016, Facebook, Inc. 3 * All rights reserved. 4 * 5 * This source code is licensed under the BSD-style license found in the 6 * LICENSE file in the root directory of this source tree. An additional grant 7 * of patent rights can be found in the PATENTS file in the same directory. 8 */ 9 10 #ifndef FATAL_INCLUDE_fatal_type_call_traits_h 11 #define FATAL_INCLUDE_fatal_type_call_traits_h 12 13 #include <fatal/preprocessor.h> 14 #include <fatal/type/apply.h> 15 #include <fatal/type/sequence.h> 16 17 #include <utility> 18 19 namespace fatal { 20 namespace detail { 21 namespace call_traits_impl { 22 23 template <typename T> T arg(); 24 25 template <bool> struct call_if; 26 27 } // namespace call_traits_impl { 28 } // namespace detail { 29 30 /** 31 * TODO: DOCUMENT AND TEST 32 * 33 * @author: Marcelo Juchem <marcelo@fb.com> 34 */ 35 struct ctor_call_traits { 36 template <typename T> 37 struct automatic { 38 using type = T; 39 automaticctor_call_traits::automatic40 constexpr inline automatic() {} 41 42 template <typename... UArgs> constructctor_call_traits::automatic43 constexpr static inline T construct(UArgs &&...args) { 44 return T(std::forward<UArgs>(args)...); 45 } 46 47 template <typename... UArgs> operatorctor_call_traits::automatic48 constexpr T inline operator ()(UArgs &&...args) const { 49 return construct(std::forward<UArgs>(args)...); 50 } 51 }; 52 53 template <typename T> 54 struct dynamic { 55 using type = T; 56 dynamicctor_call_traits::dynamic57 constexpr inline dynamic() {} 58 59 template <typename... UArgs> constructctor_call_traits::dynamic60 constexpr static inline T *construct(UArgs &&...args) { 61 return new T(std::forward<UArgs>(args)...); 62 } 63 64 template <typename... UArgs> operatorctor_call_traits::dynamic65 constexpr inline T *operator ()(UArgs &&...args) const { 66 return construct(std::forward<UArgs>(args)...); 67 } 68 }; 69 70 template <typename T> 71 struct placement { 72 using type = T; 73 placementctor_call_traits::placement74 constexpr inline placement() {} 75 76 template <typename... UArgs> constructctor_call_traits::placement77 constexpr static T *construct(T *pointer, UArgs &&...args) { 78 return new (pointer) T(std::forward<UArgs>(args)...); 79 } 80 81 template <typename... UArgs> operatorctor_call_traits::placement82 constexpr inline T *operator ()(T *pointer, UArgs &&...args) const { 83 return construct(pointer, std::forward<UArgs>(args)...); 84 } 85 }; 86 }; 87 88 /** 89 * TODO: DOCUMENT AND TEST 90 * 91 * @author: Marcelo Juchem <marcelo@fb.com> 92 */ 93 class call_operator_traits { 94 template <typename... Args> 95 struct is_impl { 96 template < 97 typename T, 98 typename = decltype( 99 detail::call_traits_impl::arg<T>()( 100 detail::call_traits_impl::arg<Args>()... 101 ) 102 ) 103 > 104 static std::true_type sfinae(T *); 105 106 template <typename...> 107 static std::false_type sfinae(...); 108 }; 109 110 public: call_operator_traits()111 constexpr call_operator_traits() {} 112 113 template <typename T, typename... UArgs> 114 static constexpr inline auto call(T &&subject, UArgs &&...args) 115 noexcept(noexcept(subject(std::forward<UArgs>(args)...))) 116 -> decltype(subject(std::forward<UArgs>(args)...)) 117 { return subject(std::forward<UArgs>(args)...); } 118 119 template <typename T, typename... UArgs> 120 constexpr inline auto operator ()(T &&subject, UArgs &&...args) const 121 noexcept( 122 noexcept(call(std::forward<T>(subject), std::forward<UArgs>(args)...)) 123 ) 124 -> decltype(call(std::forward<T>(subject), std::forward<UArgs>(args)...)) 125 { return call(std::forward<T>(subject), std::forward<UArgs>(args)...); } 126 127 /** 128 * TODO: DOCUMENT 129 * 130 * Example: 131 * 132 * struct Foo { 133 * void operator ()() {} 134 * void operator ()(int i, std::string s) {} 135 * }; 136 * 137 * auto const lambda_is = [](int, std::string) {}; 138 * using lambda = decltype(lambda_is); 139 * 140 * cout << std::boolalpha 141 * << call_operator_traits::supports<Foo>::value 142 * << ' ' << std::boolalpha 143 * << call_operator_traits::supports<Foo, int>::value 144 * << ' ' << std::boolalpha 145 * << call_operator_traits::supports<Foo, int, double>::value 146 * << ' ' << std::boolalpha 147 * << call_operator_traits::supports<Foo, int, std::string>::value 148 * << std::endl 149 * << ' ' << std::boolalpha 150 * << call_operator_traits::supports<lambda>::value 151 * << ' ' << std::boolalpha 152 * << call_operator_traits::supports<lambda, int>::value 153 * << ' ' << std::boolalpha 154 * << call_operator_traits::supports<lambda, int, double>::value 155 * << ' ' << std::boolalpha 156 * << call_operator_traits::supports<lambda, int, std::string>::value; 157 * 158 * Outputs: 159 * true false false true 160 * false false false true 161 * 162 * @author: Marcelo Juchem <marcelo@fb.com> 163 */ 164 template <typename T, typename... Args> 165 using supports = decltype( 166 is_impl<Args...>::template sfinae(static_cast<T *>(nullptr)) 167 ); 168 }; 169 170 /** 171 * TODO: DOCUMENT AND TEST 172 * 173 * @author: Marcelo Juchem <marcelo@fb.com> 174 */ 175 #define FATAL_CALL_TRAITS(Name, ...) \ 176 FATAL_IMPL_CALL_TRAITS( \ 177 Name, \ 178 FATAL_UID(FATAL_CAT(Name, _call_traits_impl)), \ 179 __VA_ARGS__ \ 180 ) 181 #define FATAL_IMPL_CALL_TRAITS(Name, Impl, ...) \ 182 class Impl { \ 183 template <typename... UArgs> \ 184 struct member_fn_supports_impl { \ 185 template < \ 186 typename U, \ 187 typename = decltype( \ 188 ::fatal::detail::call_traits_impl::arg<U>().__VA_ARGS__( \ 189 ::fatal::detail::call_traits_impl::arg<UArgs>()... \ 190 ) \ 191 ) \ 192 > \ 193 static ::std::true_type sfinae(U *); \ 194 \ 195 template <typename...> \ 196 static ::std::false_type sfinae(...); \ 197 }; \ 198 \ 199 template <typename... UArgs> \ 200 struct static_member_supports_impl { \ 201 template < \ 202 typename U, \ 203 typename = decltype( \ 204 U::__VA_ARGS__( \ 205 ::fatal::detail::call_traits_impl::arg<UArgs>()... \ 206 ) \ 207 ) \ 208 > \ 209 static ::std::true_type sfinae(U *); \ 210 \ 211 template <typename...> \ 212 static ::std::false_type sfinae(...); \ 213 }; \ 214 \ 215 FATAL_S(name_str, FATAL_TO_STR(__VA_ARGS__)); \ 216 \ 217 public: \ 218 using name = name_str; \ 219 \ 220 struct member_function { \ 221 using name = name_str; \ 222 \ 223 constexpr member_function() {} \ 224 \ 225 template <typename U> \ 226 struct bind { \ 227 template <typename... UArgs> \ 228 using supports = decltype( \ 229 member_fn_supports_impl<UArgs...>::template sfinae( \ 230 static_cast<typename ::std::remove_reference<U>::type *>(nullptr) \ 231 ) \ 232 ); \ 233 }; \ 234 \ 235 template <typename U, typename... UArgs> \ 236 using supports = typename bind<U>::template supports<UArgs...>; \ 237 \ 238 template <typename U, typename... UArgs> \ 239 using result = decltype( \ 240 ::std::declval<U>().__VA_ARGS__(::std::declval<UArgs>()...) \ 241 ); \ 242 \ 243 template <typename U, typename... UArgs> \ 244 static constexpr inline auto call(U &&subject, UArgs &&...args) \ 245 -> decltype( \ 246 ::std::forward<U>(subject).__VA_ARGS__( \ 247 ::std::forward<UArgs>(args)... \ 248 ) \ 249 ) \ 250 { \ 251 return ::std::forward<U>(subject).__VA_ARGS__( \ 252 ::std::forward<UArgs>(args)... \ 253 ); \ 254 } \ 255 \ 256 template <typename U, typename... UArgs> \ 257 constexpr inline auto operator ()(U &&subject, UArgs &&...args) const \ 258 -> decltype( \ 259 call(::std::forward<U>(subject), ::std::forward<UArgs>(args)...) \ 260 ) \ 261 { \ 262 return call( \ 263 ::std::forward<U>(subject), \ 264 ::std::forward<UArgs>(args)... \ 265 ); \ 266 } \ 267 }; \ 268 \ 269 struct static_member { \ 270 using name = name_str; \ 271 \ 272 template <typename U> \ 273 class bind { \ 274 template <typename V, typename... UArgs> \ 275 static constexpr inline auto call_impl(UArgs &&...args) \ 276 -> decltype(V::__VA_ARGS__(::std::forward<UArgs>(args)...)) \ 277 { return V::__VA_ARGS__(::std::forward<UArgs>(args)...); } \ 278 \ 279 public: \ 280 constexpr inline bind() {} \ 281 \ 282 using type = U; \ 283 \ 284 template <typename... UArgs> \ 285 using supports = decltype( \ 286 static_member_supports_impl<UArgs...>::sfinae( \ 287 static_cast<U *>(nullptr) \ 288 ) \ 289 ); \ 290 \ 291 template <typename... UArgs> \ 292 using result = decltype(call_impl<type>(::std::declval<UArgs>()...)); \ 293 \ 294 template <typename... UArgs> \ 295 static constexpr inline auto call(UArgs &&...args) \ 296 -> decltype(call_impl<type>(::std::forward<UArgs>(args)...)) \ 297 { return call_impl<type>(::std::forward<UArgs>(args)...); } \ 298 \ 299 template <typename... UArgs> \ 300 constexpr inline auto operator ()(UArgs &&...args) const \ 301 -> decltype(call_impl<type>(::std::forward<UArgs>(args)...)) \ 302 { return call_impl<type>(::std::forward<UArgs>(args)...); } \ 303 }; \ 304 \ 305 template <typename U, typename... UArgs> \ 306 static constexpr inline auto call(UArgs &&...args) \ 307 -> decltype(bind<U>::call(::std::forward<UArgs>(args)...)) \ 308 { return bind<U>::call(::std::forward<UArgs>(args)...); } \ 309 \ 310 template <typename U, typename... UArgs> \ 311 using supports = typename bind<U>::template supports<UArgs...>; \ 312 \ 313 template <typename U, typename... UArgs> \ 314 using result = typename bind<U>::template result<UArgs...>; \ 315 }; \ 316 }; \ 317 \ 318 using Name = Impl 319 320 /** 321 * Some pre-instantiated call traits for common function names. 322 * 323 * @author: Marcelo Juchem <marcelo@fb.com> 324 */ 325 struct call_traits { 326 # define FATAL_CALL_TRAITS_IMPL(Name) FATAL_CALL_TRAITS(Name, Name) 327 328 FATAL_CALL_TRAITS_IMPL(abort); 329 FATAL_CALL_TRAITS_IMPL(absolute); 330 FATAL_CALL_TRAITS_IMPL(add); 331 FATAL_CALL_TRAITS_IMPL(advance); 332 FATAL_CALL_TRAITS_IMPL(append); 333 FATAL_CALL_TRAITS_IMPL(append_to); 334 FATAL_CALL_TRAITS_IMPL(apply); 335 FATAL_CALL_TRAITS_IMPL(args); 336 FATAL_CALL_TRAITS_IMPL(argument); 337 FATAL_CALL_TRAITS_IMPL(arguments); 338 FATAL_CALL_TRAITS_IMPL(assign); 339 FATAL_CALL_TRAITS_IMPL(at); 340 FATAL_CALL_TRAITS_IMPL(back); 341 FATAL_CALL_TRAITS_IMPL(begin); 342 FATAL_CALL_TRAITS_IMPL(binary_search); 343 FATAL_CALL_TRAITS_IMPL(bind); 344 FATAL_CALL_TRAITS_IMPL(bootstrap); 345 FATAL_CALL_TRAITS_IMPL(byte); 346 FATAL_CALL_TRAITS_IMPL(bytes); 347 FATAL_CALL_TRAITS_IMPL(c_str); 348 FATAL_CALL_TRAITS_IMPL(call); 349 FATAL_CALL_TRAITS_IMPL(cancel); 350 FATAL_CALL_TRAITS_IMPL(capacity); 351 FATAL_CALL_TRAITS_IMPL(cbegin); 352 FATAL_CALL_TRAITS_IMPL(cend); 353 FATAL_CALL_TRAITS_IMPL(center); 354 FATAL_CALL_TRAITS_IMPL(check); 355 FATAL_CALL_TRAITS_IMPL(child); 356 FATAL_CALL_TRAITS_IMPL(children); 357 FATAL_CALL_TRAITS_IMPL(clean); 358 FATAL_CALL_TRAITS_IMPL(clean_up); 359 FATAL_CALL_TRAITS_IMPL(cleanup); 360 FATAL_CALL_TRAITS_IMPL(clear); 361 FATAL_CALL_TRAITS_IMPL(clone); 362 FATAL_CALL_TRAITS_IMPL(compare); 363 FATAL_CALL_TRAITS_IMPL(compress); 364 FATAL_CALL_TRAITS_IMPL(concat); 365 FATAL_CALL_TRAITS_IMPL(concatenate); 366 FATAL_CALL_TRAITS_IMPL(condition); 367 FATAL_CALL_TRAITS_IMPL(config); 368 FATAL_CALL_TRAITS_IMPL(configuration); 369 FATAL_CALL_TRAITS_IMPL(configure); 370 FATAL_CALL_TRAITS_IMPL(construct); 371 FATAL_CALL_TRAITS_IMPL(contains); 372 FATAL_CALL_TRAITS_IMPL(convert); 373 FATAL_CALL_TRAITS_IMPL(copy); 374 FATAL_CALL_TRAITS_IMPL(count); 375 FATAL_CALL_TRAITS_IMPL(cptr); 376 FATAL_CALL_TRAITS_IMPL(crbegin); 377 FATAL_CALL_TRAITS_IMPL(cref); 378 FATAL_CALL_TRAITS_IMPL(crend); 379 FATAL_CALL_TRAITS_IMPL(data); 380 FATAL_CALL_TRAITS_IMPL(decode); 381 FATAL_CALL_TRAITS_IMPL(dequeue); 382 FATAL_CALL_TRAITS_IMPL(descriptor); 383 FATAL_CALL_TRAITS_IMPL(deserialize); 384 FATAL_CALL_TRAITS_IMPL(destroy); 385 FATAL_CALL_TRAITS_IMPL(emplace); 386 FATAL_CALL_TRAITS_IMPL(emplace_back); 387 FATAL_CALL_TRAITS_IMPL(emplace_front); 388 FATAL_CALL_TRAITS_IMPL(empty); 389 FATAL_CALL_TRAITS_IMPL(encode); 390 FATAL_CALL_TRAITS_IMPL(end); 391 FATAL_CALL_TRAITS_IMPL(enqueue); 392 FATAL_CALL_TRAITS_IMPL(equal); 393 FATAL_CALL_TRAITS_IMPL(equal_range); 394 FATAL_CALL_TRAITS_IMPL(erase); 395 FATAL_CALL_TRAITS_IMPL(exact); 396 FATAL_CALL_TRAITS_IMPL(exception); 397 FATAL_CALL_TRAITS_IMPL(exit); 398 FATAL_CALL_TRAITS_IMPL(extension); 399 FATAL_CALL_TRAITS_IMPL(find); 400 FATAL_CALL_TRAITS_IMPL(find_first_not_of); 401 FATAL_CALL_TRAITS_IMPL(find_first_of); 402 FATAL_CALL_TRAITS_IMPL(find_last_not_of); 403 FATAL_CALL_TRAITS_IMPL(find_last_of); 404 FATAL_CALL_TRAITS_IMPL(finish); 405 FATAL_CALL_TRAITS_IMPL(finished); 406 FATAL_CALL_TRAITS_IMPL(first); 407 FATAL_CALL_TRAITS_IMPL(for_each); 408 FATAL_CALL_TRAITS_IMPL(foreach); 409 FATAL_CALL_TRAITS_IMPL(foreach_if); 410 FATAL_CALL_TRAITS_IMPL(fork); 411 FATAL_CALL_TRAITS_IMPL(forward); 412 FATAL_CALL_TRAITS_IMPL(fourth); 413 FATAL_CALL_TRAITS_IMPL(freeze); 414 FATAL_CALL_TRAITS_IMPL(from); 415 FATAL_CALL_TRAITS_IMPL(front); 416 FATAL_CALL_TRAITS_IMPL(get); 417 FATAL_CALL_TRAITS_IMPL(get_pointer); 418 FATAL_CALL_TRAITS_IMPL(get_reference); 419 FATAL_CALL_TRAITS_IMPL(getline); 420 FATAL_CALL_TRAITS_IMPL(go); 421 FATAL_CALL_TRAITS_IMPL(halt); 422 FATAL_CALL_TRAITS_IMPL(hash); 423 FATAL_CALL_TRAITS_IMPL(id); 424 FATAL_CALL_TRAITS_IMPL(index); 425 FATAL_CALL_TRAITS_IMPL(index_of); 426 FATAL_CALL_TRAITS_IMPL(info); 427 FATAL_CALL_TRAITS_IMPL(init); 428 FATAL_CALL_TRAITS_IMPL(initialize); 429 FATAL_CALL_TRAITS_IMPL(inject); 430 FATAL_CALL_TRAITS_IMPL(inner); 431 FATAL_CALL_TRAITS_IMPL(insert); 432 FATAL_CALL_TRAITS_IMPL(join); 433 FATAL_CALL_TRAITS_IMPL(joinable); 434 FATAL_CALL_TRAITS_IMPL(kind); 435 FATAL_CALL_TRAITS_IMPL(last); 436 FATAL_CALL_TRAITS_IMPL(left); 437 FATAL_CALL_TRAITS_IMPL(length); 438 FATAL_CALL_TRAITS_IMPL(lift); 439 FATAL_CALL_TRAITS_IMPL(limit); 440 FATAL_CALL_TRAITS_IMPL(list); 441 FATAL_CALL_TRAITS_IMPL(lock); 442 FATAL_CALL_TRAITS_IMPL(longest); 443 FATAL_CALL_TRAITS_IMPL(loop); 444 FATAL_CALL_TRAITS_IMPL(lower_bound); 445 FATAL_CALL_TRAITS_IMPL(map); 446 FATAL_CALL_TRAITS_IMPL(match); 447 FATAL_CALL_TRAITS_IMPL(max); 448 FATAL_CALL_TRAITS_IMPL(max_size); 449 FATAL_CALL_TRAITS_IMPL(mean); 450 FATAL_CALL_TRAITS_IMPL(median); 451 FATAL_CALL_TRAITS_IMPL(merge); 452 FATAL_CALL_TRAITS_IMPL(mid); 453 FATAL_CALL_TRAITS_IMPL(middle); 454 FATAL_CALL_TRAITS_IMPL(mimic); 455 FATAL_CALL_TRAITS_IMPL(min); 456 FATAL_CALL_TRAITS_IMPL(move); 457 FATAL_CALL_TRAITS_IMPL(multi_append); 458 FATAL_CALL_TRAITS_IMPL(name); 459 FATAL_CALL_TRAITS_IMPL(next); 460 FATAL_CALL_TRAITS_IMPL(next_as); 461 FATAL_CALL_TRAITS_IMPL(nth_element); 462 FATAL_CALL_TRAITS_IMPL(observe); 463 FATAL_CALL_TRAITS_IMPL(off); 464 FATAL_CALL_TRAITS_IMPL(offset); 465 FATAL_CALL_TRAITS_IMPL(on); 466 FATAL_CALL_TRAITS_IMPL(outer); 467 FATAL_CALL_TRAITS_IMPL(owner); 468 FATAL_CALL_TRAITS_IMPL(parameter); 469 FATAL_CALL_TRAITS_IMPL(parameters); 470 FATAL_CALL_TRAITS_IMPL(partial); 471 FATAL_CALL_TRAITS_IMPL(partial_sort); 472 FATAL_CALL_TRAITS_IMPL(partition); 473 FATAL_CALL_TRAITS_IMPL(pause); 474 FATAL_CALL_TRAITS_IMPL(payload); 475 FATAL_CALL_TRAITS_IMPL(pending); 476 FATAL_CALL_TRAITS_IMPL(piece); 477 FATAL_CALL_TRAITS_IMPL(pieces); 478 FATAL_CALL_TRAITS_IMPL(pinpoint); 479 FATAL_CALL_TRAITS_IMPL(pointer); 480 FATAL_CALL_TRAITS_IMPL(poll); 481 FATAL_CALL_TRAITS_IMPL(pop); 482 FATAL_CALL_TRAITS_IMPL(pop_back); 483 FATAL_CALL_TRAITS_IMPL(pop_front); 484 FATAL_CALL_TRAITS_IMPL(predicate); 485 FATAL_CALL_TRAITS_IMPL(prefix); 486 FATAL_CALL_TRAITS_IMPL(prefixes); 487 FATAL_CALL_TRAITS_IMPL(prev); 488 FATAL_CALL_TRAITS_IMPL(previous); 489 FATAL_CALL_TRAITS_IMPL(properties); 490 FATAL_CALL_TRAITS_IMPL(property); 491 FATAL_CALL_TRAITS_IMPL(ptr); 492 FATAL_CALL_TRAITS_IMPL(push); 493 FATAL_CALL_TRAITS_IMPL(push_back); 494 FATAL_CALL_TRAITS_IMPL(push_front); 495 FATAL_CALL_TRAITS_IMPL(put); 496 FATAL_CALL_TRAITS_IMPL(queue); 497 FATAL_CALL_TRAITS_IMPL(quit); 498 FATAL_CALL_TRAITS_IMPL(rbegin); 499 FATAL_CALL_TRAITS_IMPL(read); 500 FATAL_CALL_TRAITS_IMPL(ref); 501 FATAL_CALL_TRAITS_IMPL(reference); 502 FATAL_CALL_TRAITS_IMPL(rehash); 503 FATAL_CALL_TRAITS_IMPL(relative); 504 FATAL_CALL_TRAITS_IMPL(release); 505 FATAL_CALL_TRAITS_IMPL(remove); 506 FATAL_CALL_TRAITS_IMPL(rend); 507 FATAL_CALL_TRAITS_IMPL(replace); 508 FATAL_CALL_TRAITS_IMPL(reserve); 509 FATAL_CALL_TRAITS_IMPL(reset); 510 FATAL_CALL_TRAITS_IMPL(resize); 511 FATAL_CALL_TRAITS_IMPL(resume); 512 FATAL_CALL_TRAITS_IMPL(reverse); 513 FATAL_CALL_TRAITS_IMPL(rfind); 514 FATAL_CALL_TRAITS_IMPL(right); 515 FATAL_CALL_TRAITS_IMPL(rng); 516 FATAL_CALL_TRAITS_IMPL(rotate); 517 FATAL_CALL_TRAITS_IMPL(run); 518 FATAL_CALL_TRAITS_IMPL(search); 519 FATAL_CALL_TRAITS_IMPL(second); 520 FATAL_CALL_TRAITS_IMPL(seek); 521 FATAL_CALL_TRAITS_IMPL(select); 522 FATAL_CALL_TRAITS_IMPL(serialize); 523 FATAL_CALL_TRAITS_IMPL(set); 524 FATAL_CALL_TRAITS_IMPL(setup); 525 FATAL_CALL_TRAITS_IMPL(shortest); 526 FATAL_CALL_TRAITS_IMPL(shrink_to_fit); 527 FATAL_CALL_TRAITS_IMPL(shuffle); 528 FATAL_CALL_TRAITS_IMPL(shutdown); 529 FATAL_CALL_TRAITS_IMPL(signature); 530 FATAL_CALL_TRAITS_IMPL(size); 531 FATAL_CALL_TRAITS_IMPL(slice); 532 FATAL_CALL_TRAITS_IMPL(sort); 533 FATAL_CALL_TRAITS_IMPL(source); 534 FATAL_CALL_TRAITS_IMPL(spawn); 535 FATAL_CALL_TRAITS_IMPL(split); 536 FATAL_CALL_TRAITS_IMPL(split_step); 537 FATAL_CALL_TRAITS_IMPL(stable_sort); 538 FATAL_CALL_TRAITS_IMPL(stack); 539 FATAL_CALL_TRAITS_IMPL(standard_deviation); 540 FATAL_CALL_TRAITS_IMPL(start); 541 FATAL_CALL_TRAITS_IMPL(stddev); 542 FATAL_CALL_TRAITS_IMPL(steal); 543 FATAL_CALL_TRAITS_IMPL(stop); 544 FATAL_CALL_TRAITS_IMPL(str); 545 FATAL_CALL_TRAITS_IMPL(string); 546 FATAL_CALL_TRAITS_IMPL(substr); 547 FATAL_CALL_TRAITS_IMPL(suspend); 548 FATAL_CALL_TRAITS_IMPL(swap); 549 FATAL_CALL_TRAITS_IMPL(thaw); 550 FATAL_CALL_TRAITS_IMPL(third); 551 FATAL_CALL_TRAITS_IMPL(to); 552 FATAL_CALL_TRAITS_IMPL(to_str); 553 FATAL_CALL_TRAITS_IMPL(to_string); 554 FATAL_CALL_TRAITS_IMPL(to_wstring); 555 FATAL_CALL_TRAITS_IMPL(transcode); 556 FATAL_CALL_TRAITS_IMPL(transform); 557 FATAL_CALL_TRAITS_IMPL(try_emplace); 558 FATAL_CALL_TRAITS_IMPL(try_get); 559 FATAL_CALL_TRAITS_IMPL(try_lock); 560 FATAL_CALL_TRAITS_IMPL(try_set); 561 FATAL_CALL_TRAITS_IMPL(try_to); 562 FATAL_CALL_TRAITS_IMPL(turn); 563 FATAL_CALL_TRAITS_IMPL(type); 564 FATAL_CALL_TRAITS_IMPL(unique); 565 FATAL_CALL_TRAITS_IMPL(unlock); 566 FATAL_CALL_TRAITS_IMPL(update); 567 FATAL_CALL_TRAITS_IMPL(upper_bound); 568 FATAL_CALL_TRAITS_IMPL(value); 569 FATAL_CALL_TRAITS_IMPL(variance); 570 FATAL_CALL_TRAITS_IMPL(visit); 571 FATAL_CALL_TRAITS_IMPL(visit_if); 572 FATAL_CALL_TRAITS_IMPL(which); 573 FATAL_CALL_TRAITS_IMPL(with); 574 FATAL_CALL_TRAITS_IMPL(write); 575 576 # undef FATAL_CALL_TRAITS_IMPL 577 }; 578 579 /** 580 * TODO: DOCUMENT 581 * 582 * @author: Marcelo Juchem <marcelo@fb.com> 583 */ 584 #define FATAL_FREE_FUNCTION_CALL_TRAITS(Name, ...) \ 585 FATAL_IMPL_FREE_FUNCTION_CALL_TRAITS( \ 586 Name, \ 587 FATAL_UID(FATAL_CAT(Name, _free_fn_call_traits_impl)), \ 588 __VA_ARGS__ \ 589 ) 590 591 #define FATAL_IMPL_FREE_FUNCTION_CALL_TRAITS(Name, Impl, ...) \ 592 struct Impl { \ 593 FATAL_S(name, FATAL_TO_STR(__VA_ARGS__)); \ 594 \ 595 constexpr inline Impl() {} \ 596 \ 597 template <typename... UArgs> \ 598 static constexpr inline auto call(UArgs &&...args) \ 599 -> decltype(__VA_ARGS__(::std::forward<UArgs>(args)...)) \ 600 { return __VA_ARGS__(::std::forward<UArgs>(args)...); } \ 601 \ 602 template <typename... UArgs> \ 603 constexpr inline auto operator ()(UArgs &&...args) const \ 604 -> decltype(call(::std::forward<UArgs>(args)...)) \ 605 { return call(::std::forward<UArgs>(args)...); } \ 606 }; \ 607 \ 608 using Name = Impl 609 610 /** 611 * Conditionally calls a function according to the given predicate. 612 * 613 * The provided call traits is used to decide which function to call, perfectly 614 * forwarding the given parameters to it. 615 * 616 * When the predicate evaluates to false, `Fallback` is instantiated and its 617 * call operator is called, perfectly forwarding the parameters to it. 618 * 619 * An optional list of template parameters `Args` can also be passed to the 620 * function. 621 * 622 * The predicate is a type template. It receives the optional list of template 623 * parameters and the types of the arguments given to `call_if`, and must 624 * evaluate to a type similar to `std::integral_constant` of type `bool`. 625 * In other words, `Predicate<Args..., UArgs...>::value` is used to decide 626 * whether to call the function, through the call traits, or the fallback. 627 * 628 * Default predicate calls the function if it exists and supported the given 629 * parameters, otherwise it calls the fallback. 630 * 631 * Example: 632 * 633 * struct fallback { 634 * template <typename... Args> 635 * int operator ()(Args &&...) { return 98765; } 636 * }; 637 * 638 * struct foo { 639 * template <typename T> 640 * T bar() { return T(12345); } 641 * 642 * double bar(char const *, bool) { return 5.6; } 643 * 644 * std::string baz(std::size_t n = 1) { return std::string(n, 'x'); } 645 * 646 * template <typename... Args> 647 * std::size_t baz(char const *s) { 648 * return std::strlen(s) + sizeof...(Args); 649 * } 650 * }; 651 * 652 * FATAL_CALL_TRAITS(bar_traits, bar); 653 * using member_fn = bar_traits::member_function; 654 * 655 * template <typename T, typename... Args> 656 * using member_pred = member_fn::supports<T, Args...>; 657 * 658 * foo f; 659 * 660 * // yields `12345` as an `int` 661 * auto result1 = call_if<member_fn, fallback, member_pred>(f); 662 * 663 * // yields `12345` as a `double` 664 * auto result2 = call_if<member_fn, fallback, member_pred, double>(f); 665 * 666 * // yields `98765` 667 * auto result3 = call_if<member_fn, fallback, member_pred>( 668 * f, "hello", "world", 143 669 * ); 670 * 671 * // yields `5.6` 672 * auto result4 = call_if<member_fn, fallback, member_pred>(f, "test", true); 673 * 674 * // yields `98765` 675 * auto result5 = call_if<member_fn, fallback, member_pred>(f, 10); 676 * 677 * FATAL_CALL_TRAITS(baz_traits, baz); 678 * using static_fn = baz_traits::static_member::bind<foo>; 679 * 680 * template <typename... Args> 681 * using static_pred = static_fn::supports<Args...>; 682 * 683 * // yields `"xxxxx"` 684 * auto result6 = call_if<static_fn, fallback, static_pred>(5); 685 * 686 * // yields `"x"` 687 * auto result7 = call_if<static_fn, fallback, static_pred>(); 688 * 689 * // yields `98765` 690 * auto result8 = call_if<static_fn, fallback, static_pred>("hello", "world"); 691 * 692 * // yields `4` 693 * auto result9 = call_if<static_fn, fallback, static_pred>("test"); 694 * 695 * // yields `6` 696 * auto result10 = call_if<static_fn, fallback, static_pred, void, bool>( 697 * "test" 698 * ); 699 * 700 * @author: Marcelo Juchem <marcelo@fb.com> 701 */ 702 template < 703 typename CallTraits, 704 typename Fallback, 705 template <typename...> class Predicate, 706 typename... Args, 707 typename... UArgs 708 > 709 constexpr inline auto call_if(UArgs &&...args) 710 -> decltype( 711 detail::call_traits_impl::call_if< 712 apply_args<Predicate, Args..., UArgs...>::value 713 >::template call<CallTraits, Fallback, Args...>( 714 std::forward<UArgs>(args)... 715 ) 716 ) 717 { 718 return detail::call_traits_impl::call_if< 719 apply_args<Predicate, Args..., UArgs...>::value 720 >::template call<CallTraits, Fallback, Args...>( 721 std::forward<UArgs>(args)... 722 ); 723 } 724 725 /** 726 * Convenient specialization of `call_if` that calls a function if it exists 727 * and the desired overload is supported, or calls the fallback otherwise. 728 * 729 * The provided call traits is used to decide which function to call, perfectly 730 * forwarding the given parameters to it. 731 * 732 * An optional list of template parameters `Args` can also be passed to the 733 * function. 734 * 735 * Example: 736 * 737 * struct fallback { 738 * template <typename... Args> 739 * int operator ()(Args &&...) { return 98765; } 740 * }; 741 * 742 * struct foo { 743 * template <typename T> 744 * T bar() { return T(12345); } 745 * 746 * double bar(char const *, bool) { return 5.6; } 747 * 748 * std::string baz(std::size_t n = 1) { return std::string(n, 'x'); } 749 * 750 * template <typename... Args> 751 * std::size_t baz(char const *s) { 752 * return std::strlen(s) + sizeof...(Args); 753 * } 754 * }; 755 * 756 * FATAL_CALL_TRAITS(bar_traits, bar); 757 * using member_fn = bar_traits::member_function; 758 * 759 * foo f; 760 * 761 * // yields `12345` as an `int` 762 * auto result1 = call_if_supported<member_fn, fallback>(f); 763 * 764 * // yields `12345` as a `double` 765 * auto result2 = call_if_supported<member_fn, fallback, double>(f); 766 * 767 * // yields `98765` 768 * auto result3 = call_if_supported<member_fn, fallback>( 769 * f, "hello", "world", 143 770 * ); 771 * 772 * // yields `5.6` 773 * auto result4 = call_if_supported<member_fn, fallback>(f, "test", true); 774 * 775 * // yields `98765` 776 * auto result5 = call_if_supported<member_fn, fallback>(f, 10); 777 * 778 * FATAL_CALL_TRAITS(baz_traits, baz); 779 * using static_fn = baz_traits::static_member::bind<foo>; 780 * 781 * // yields `"xxxxx"` 782 * auto result6 = call_if_supported<static_fn, fallback>(5); 783 * 784 * // yields `"x"` 785 * auto result7 = call_if_supported<static_fn, fallback>(); 786 * 787 * // yields `98765` 788 * auto result8 = call_if_supported<static_fn, fallback>("hello", "world"); 789 * 790 * // yields `4` 791 * auto result9 = call_if_supported<static_fn, fallback>("test"); 792 * 793 * // yields `6` 794 * auto result10 = call_if_supported<static_fn, fallback, void, bool>("test"); 795 * 796 * @author: Marcelo Juchem <marcelo@fb.com> 797 */ 798 template < 799 typename CallTraits, typename Fallback, typename... Args, typename... UArgs 800 > 801 constexpr inline auto call_if_supported(UArgs &&...args) 802 -> decltype( 803 call_if<CallTraits, Fallback, CallTraits::template supports, Args...>( 804 std::forward<UArgs>(args)... 805 ) 806 ) 807 { 808 return call_if<CallTraits, Fallback, CallTraits::template supports, Args...>( 809 std::forward<UArgs>(args)... 810 ); 811 } 812 813 //////////////////////////// 814 // IMPLEMENTATION DETAILS // 815 //////////////////////////// 816 817 namespace detail { 818 namespace call_traits_impl { 819 820 template <bool> 821 struct call_if { 822 template <typename Traits, typename, typename... Args, typename... UArgs> 823 static constexpr inline auto call(UArgs &&...args) 824 -> decltype(Traits::template call<Args...>(std::forward<UArgs>(args)...)) 825 { 826 return Traits::template call<Args...>(std::forward<UArgs>(args)...); 827 } 828 }; 829 830 template <> 831 struct call_if<false> { 832 template <typename, typename Fn, typename... Args, typename... UArgs> 833 static constexpr inline auto call(UArgs &&...args) 834 -> decltype(Fn()(std::forward<UArgs>(args)...)) 835 { 836 return Fn()(std::forward<UArgs>(args)...); 837 } 838 }; 839 840 } // namespace call_traits_impl { 841 } // namespace detail { 842 } // namespace fatal { 843 844 #endif // FATAL_INCLUDE_fatal_type_call_traits_h 845