1# =========================================================================== 2# https://www.gnu.org/software/autoconf-archive/ax_cxx_compile_stdcxx.html 3# =========================================================================== 4# 5# SYNOPSIS 6# 7# AX_CXX_COMPILE_STDCXX(VERSION, [ext|noext], [mandatory|optional]) 8# 9# DESCRIPTION 10# 11# Check for baseline language coverage in the compiler for the specified 12# version of the C++ standard. If necessary, add switches to CXX and 13# CXXCPP to enable support. VERSION may be '11' (for the C++11 standard) 14# or '14' (for the C++14 standard). 15# 16# The second argument, if specified, indicates whether you insist on an 17# extended mode (e.g. -std=gnu++11) or a strict conformance mode (e.g. 18# -std=c++11). If neither is specified, you get whatever works, with 19# preference for an extended mode. 20# 21# The third argument, if specified 'mandatory' or if left unspecified, 22# indicates that baseline support for the specified C++ standard is 23# required and that the macro should error out if no mode with that 24# support is found. If specified 'optional', then configuration proceeds 25# regardless, after defining HAVE_CXX${VERSION} if and only if a 26# supporting mode is found. 27# 28# LICENSE 29# 30# Copyright (c) 2008 Benjamin Kosnik <bkoz@redhat.com> 31# Copyright (c) 2012 Zack Weinberg <zackw@panix.com> 32# Copyright (c) 2013 Roy Stogner <roystgnr@ices.utexas.edu> 33# Copyright (c) 2014, 2015 Google Inc.; contributed by Alexey Sokolov <sokolov@google.com> 34# Copyright (c) 2015 Paul Norman <penorman@mac.com> 35# Copyright (c) 2015 Moritz Klammler <moritz@klammler.eu> 36# Copyright (c) 2016 Krzesimir Nowak <qdlacz@gmail.com> 37# 38# Copying and distribution of this file, with or without modification, are 39# permitted in any medium without royalty provided the copyright notice 40# and this notice are preserved. This file is offered as-is, without any 41# warranty. 42 43#serial 7 44 45dnl This macro is based on the code from the AX_CXX_COMPILE_STDCXX_11 macro 46dnl (serial version number 13). 47 48AX_REQUIRE_DEFINED([AC_MSG_WARN]) 49AC_DEFUN([AX_CXX_COMPILE_STDCXX], [dnl 50 m4_if([$1], [11], [ax_cxx_compile_alternatives="11 0x"], 51 [$1], [14], [ax_cxx_compile_alternatives="14 1y"], 52 [$1], [17], [ax_cxx_compile_alternatives="17 1z"], 53 [m4_fatal([invalid first argument `$1' to AX_CXX_COMPILE_STDCXX])])dnl 54 m4_if([$2], [], [], 55 [$2], [ext], [], 56 [$2], [noext], [], 57 [m4_fatal([invalid second argument `$2' to AX_CXX_COMPILE_STDCXX])])dnl 58 m4_if([$3], [], [ax_cxx_compile_cxx$1_required=true], 59 [$3], [mandatory], [ax_cxx_compile_cxx$1_required=true], 60 [$3], [optional], [ax_cxx_compile_cxx$1_required=false], 61 [m4_fatal([invalid third argument `$3' to AX_CXX_COMPILE_STDCXX])]) 62 AC_LANG_PUSH([C++])dnl 63 ac_success=no 64 AC_CACHE_CHECK(whether $CXX supports C++$1 features by default, 65 ax_cv_cxx_compile_cxx$1, 66 [AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_testbody_$1])], 67 [ax_cv_cxx_compile_cxx$1=yes], 68 [ax_cv_cxx_compile_cxx$1=no])]) 69 if test x$ax_cv_cxx_compile_cxx$1 = xyes; then 70 ac_success=yes 71 fi 72 73 m4_if([$2], [noext], [], [dnl 74 if test x$ac_success = xno; then 75 for alternative in ${ax_cxx_compile_alternatives}; do 76 switch="-std=gnu++${alternative}" 77 cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx$1_$switch]) 78 AC_CACHE_CHECK(whether $CXX supports C++$1 features with $switch, 79 $cachevar, 80 [ac_save_CXX="$CXX" 81 CXX="$CXX $switch" 82 AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_testbody_$1])], 83 [eval $cachevar=yes], 84 [eval $cachevar=no]) 85 CXX="$ac_save_CXX"]) 86 if eval test x\$$cachevar = xyes; then 87 CXX="$CXX $switch" 88 if test -n "$CXXCPP" ; then 89 CXXCPP="$CXXCPP $switch" 90 fi 91 ac_success=yes 92 break 93 fi 94 done 95 fi]) 96 97 m4_if([$2], [ext], [], [dnl 98 if test x$ac_success = xno; then 99 dnl HP's aCC needs +std=c++11 according to: 100 dnl http://h21007.www2.hp.com/portal/download/files/unprot/aCxx/PDF_Release_Notes/769149-001.pdf 101 dnl Cray's crayCC needs "-h std=c++11" 102 for alternative in ${ax_cxx_compile_alternatives}; do 103 for switch in -std=c++${alternative} +std=c++${alternative} "-h std=c++${alternative}"; do 104 cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx$1_$switch]) 105 AC_CACHE_CHECK(whether $CXX supports C++$1 features with $switch, 106 $cachevar, 107 [ac_save_CXX="$CXX" 108 CXX="$CXX $switch" 109 AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_testbody_$1])], 110 [eval $cachevar=yes], 111 [eval $cachevar=no]) 112 CXX="$ac_save_CXX"]) 113 if eval test x\$$cachevar = xyes; then 114 CXX="$CXX $switch" 115 if test -n "$CXXCPP" ; then 116 CXXCPP="$CXXCPP $switch" 117 fi 118 ac_success=yes 119 break 120 fi 121 done 122 if test x$ac_success = xyes; then 123 break 124 fi 125 done 126 fi]) 127 AC_LANG_POP([C++]) 128 if test x$ax_cxx_compile_cxx$1_required = xtrue; then 129 if test x$ac_success = xno; then 130 AC_MSG_ERROR([*** A compiler with support for C++$1 language features is required.]) 131 fi 132 fi 133 if test x$ac_success = xno; then 134 HAVE_CXX$1=0 135 AC_MSG_NOTICE([No compiler with C++$1 support was found]) 136 else 137 HAVE_CXX$1=1 138 AC_DEFINE(HAVE_CXX$1,1, 139 [define if the compiler supports basic C++$1 syntax]) 140 fi 141 AC_SUBST(HAVE_CXX$1) 142 m4_if([$1], [17], [AC_MSG_WARN([C++17 is not yet standardized, so the checks may change in incompatible ways anytime])]) 143]) 144 145 146dnl Test body for checking C++11 support 147 148m4_define([_AX_CXX_COMPILE_STDCXX_testbody_11], 149 _AX_CXX_COMPILE_STDCXX_testbody_new_in_11 150) 151 152 153dnl Test body for checking C++14 support 154 155m4_define([_AX_CXX_COMPILE_STDCXX_testbody_14], 156 _AX_CXX_COMPILE_STDCXX_testbody_new_in_11 157 _AX_CXX_COMPILE_STDCXX_testbody_new_in_14 158) 159 160m4_define([_AX_CXX_COMPILE_STDCXX_testbody_17], 161 _AX_CXX_COMPILE_STDCXX_testbody_new_in_11 162 _AX_CXX_COMPILE_STDCXX_testbody_new_in_14 163 _AX_CXX_COMPILE_STDCXX_testbody_new_in_17 164) 165 166dnl Tests for new features in C++11 167 168m4_define([_AX_CXX_COMPILE_STDCXX_testbody_new_in_11], [[ 169 170// If the compiler admits that it is not ready for C++11, why torture it? 171// Hopefully, this will speed up the test. 172 173#ifndef __cplusplus 174 175#error "This is not a C++ compiler" 176 177#elif __cplusplus < 201103L 178 179#error "This is not a C++11 compiler" 180 181#else 182 183namespace cxx11 184{ 185 186 namespace test_static_assert 187 { 188 189 template <typename T> 190 struct check 191 { 192 static_assert(sizeof(int) <= sizeof(T), "not big enough"); 193 }; 194 195 } 196 197 namespace test_final_override 198 { 199 200 struct Base 201 { 202 virtual void f() {} 203 }; 204 205 struct Derived : public Base 206 { 207 virtual void f() override {} 208 }; 209 210 } 211 212 namespace test_double_right_angle_brackets 213 { 214 215 template < typename T > 216 struct check {}; 217 218 typedef check<void> single_type; 219 typedef check<check<void>> double_type; 220 typedef check<check<check<void>>> triple_type; 221 typedef check<check<check<check<void>>>> quadruple_type; 222 223 } 224 225 namespace test_decltype 226 { 227 228 int 229 f() 230 { 231 int a = 1; 232 decltype(a) b = 2; 233 return a + b; 234 } 235 236 } 237 238 namespace test_type_deduction 239 { 240 241 template < typename T1, typename T2 > 242 struct is_same 243 { 244 static const bool value = false; 245 }; 246 247 template < typename T > 248 struct is_same<T, T> 249 { 250 static const bool value = true; 251 }; 252 253 template < typename T1, typename T2 > 254 auto 255 add(T1 a1, T2 a2) -> decltype(a1 + a2) 256 { 257 return a1 + a2; 258 } 259 260 int 261 test(const int c, volatile int v) 262 { 263 static_assert(is_same<int, decltype(0)>::value == true, ""); 264 static_assert(is_same<int, decltype(c)>::value == false, ""); 265 static_assert(is_same<int, decltype(v)>::value == false, ""); 266 auto ac = c; 267 auto av = v; 268 auto sumi = ac + av + 'x'; 269 auto sumf = ac + av + 1.0; 270 static_assert(is_same<int, decltype(ac)>::value == true, ""); 271 static_assert(is_same<int, decltype(av)>::value == true, ""); 272 static_assert(is_same<int, decltype(sumi)>::value == true, ""); 273 static_assert(is_same<int, decltype(sumf)>::value == false, ""); 274 static_assert(is_same<int, decltype(add(c, v))>::value == true, ""); 275 return (sumf > 0.0) ? sumi : add(c, v); 276 } 277 278 } 279 280 namespace test_noexcept 281 { 282 283 int f() { return 0; } 284 int g() noexcept { return 0; } 285 286 static_assert(noexcept(f()) == false, ""); 287 static_assert(noexcept(g()) == true, ""); 288 289 } 290 291 namespace test_constexpr 292 { 293 294 template < typename CharT > 295 unsigned long constexpr 296 strlen_c_r(const CharT *const s, const unsigned long acc) noexcept 297 { 298 return *s ? strlen_c_r(s + 1, acc + 1) : acc; 299 } 300 301 template < typename CharT > 302 unsigned long constexpr 303 strlen_c(const CharT *const s) noexcept 304 { 305 return strlen_c_r(s, 0UL); 306 } 307 308 static_assert(strlen_c("") == 0UL, ""); 309 static_assert(strlen_c("1") == 1UL, ""); 310 static_assert(strlen_c("example") == 7UL, ""); 311 static_assert(strlen_c("another\0example") == 7UL, ""); 312 313 } 314 315 namespace test_rvalue_references 316 { 317 318 template < int N > 319 struct answer 320 { 321 static constexpr int value = N; 322 }; 323 324 answer<1> f(int&) { return answer<1>(); } 325 answer<2> f(const int&) { return answer<2>(); } 326 answer<3> f(int&&) { return answer<3>(); } 327 328 void 329 test() 330 { 331 int i = 0; 332 const int c = 0; 333 static_assert(decltype(f(i))::value == 1, ""); 334 static_assert(decltype(f(c))::value == 2, ""); 335 static_assert(decltype(f(0))::value == 3, ""); 336 } 337 338 } 339 340 namespace test_uniform_initialization 341 { 342 343 struct test 344 { 345 static const int zero {}; 346 static const int one {1}; 347 }; 348 349 static_assert(test::zero == 0, ""); 350 static_assert(test::one == 1, ""); 351 352 } 353 354 namespace test_lambdas 355 { 356 357 void 358 test1() 359 { 360 auto lambda1 = [](){}; 361 auto lambda2 = lambda1; 362 lambda1(); 363 lambda2(); 364 } 365 366 int 367 test2() 368 { 369 auto a = [](int i, int j){ return i + j; }(1, 2); 370 auto b = []() -> int { return '0'; }(); 371 auto c = [=](){ return a + b; }(); 372 auto d = [&](){ return c; }(); 373 auto e = [a, &b](int x) mutable { 374 const auto identity = [](int y){ return y; }; 375 for (auto i = 0; i < a; ++i) 376 a += b--; 377 return x + identity(a + b); 378 }(0); 379 return a + b + c + d + e; 380 } 381 382 int 383 test3() 384 { 385 const auto nullary = [](){ return 0; }; 386 const auto unary = [](int x){ return x; }; 387 using nullary_t = decltype(nullary); 388 using unary_t = decltype(unary); 389 const auto higher1st = [](nullary_t f){ return f(); }; 390 const auto higher2nd = [unary](nullary_t f1){ 391 return [unary, f1](unary_t f2){ return f2(unary(f1())); }; 392 }; 393 return higher1st(nullary) + higher2nd(nullary)(unary); 394 } 395 396 } 397 398 namespace test_variadic_templates 399 { 400 401 template <int...> 402 struct sum; 403 404 template <int N0, int... N1toN> 405 struct sum<N0, N1toN...> 406 { 407 static constexpr auto value = N0 + sum<N1toN...>::value; 408 }; 409 410 template <> 411 struct sum<> 412 { 413 static constexpr auto value = 0; 414 }; 415 416 static_assert(sum<>::value == 0, ""); 417 static_assert(sum<1>::value == 1, ""); 418 static_assert(sum<23>::value == 23, ""); 419 static_assert(sum<1, 2>::value == 3, ""); 420 static_assert(sum<5, 5, 11>::value == 21, ""); 421 static_assert(sum<2, 3, 5, 7, 11, 13>::value == 41, ""); 422 423 } 424 425 // https://stackoverflow.com/questions/13728184/template-aliases-and-sfinae 426 // Clang 3.1 fails with headers of libstd++ 4.8.3 when using std::function 427 // because of this. 428 namespace test_template_alias_sfinae 429 { 430 431 struct foo {}; 432 433 template<typename T> 434 using member = typename T::member_type; 435 436 template<typename T> 437 void func(...) {} 438 439 template<typename T> 440 void func(member<T>*) {} 441 442 void test(); 443 444 void test() { func<foo>(0); } 445 446 } 447 448} // namespace cxx11 449 450#endif // __cplusplus >= 201103L 451 452]]) 453 454 455dnl Tests for new features in C++14 456 457m4_define([_AX_CXX_COMPILE_STDCXX_testbody_new_in_14], [[ 458 459// If the compiler admits that it is not ready for C++14, why torture it? 460// Hopefully, this will speed up the test. 461 462#ifndef __cplusplus 463 464#error "This is not a C++ compiler" 465 466#elif __cplusplus < 201402L 467 468#error "This is not a C++14 compiler" 469 470#else 471 472namespace cxx14 473{ 474 475 namespace test_polymorphic_lambdas 476 { 477 478 int 479 test() 480 { 481 const auto lambda = [](auto&&... args){ 482 const auto istiny = [](auto x){ 483 return (sizeof(x) == 1UL) ? 1 : 0; 484 }; 485 const int aretiny[] = { istiny(args)... }; 486 return aretiny[0]; 487 }; 488 return lambda(1, 1L, 1.0f, '1'); 489 } 490 491 } 492 493 namespace test_binary_literals 494 { 495 496 constexpr auto ivii = 0b0000000000101010; 497 static_assert(ivii == 42, "wrong value"); 498 499 } 500 501 namespace test_generalized_constexpr 502 { 503 504 template < typename CharT > 505 constexpr unsigned long 506 strlen_c(const CharT *const s) noexcept 507 { 508 auto length = 0UL; 509 for (auto p = s; *p; ++p) 510 ++length; 511 return length; 512 } 513 514 static_assert(strlen_c("") == 0UL, ""); 515 static_assert(strlen_c("x") == 1UL, ""); 516 static_assert(strlen_c("test") == 4UL, ""); 517 static_assert(strlen_c("another\0test") == 7UL, ""); 518 519 } 520 521 namespace test_lambda_init_capture 522 { 523 524 int 525 test() 526 { 527 auto x = 0; 528 const auto lambda1 = [a = x](int b){ return a + b; }; 529 const auto lambda2 = [a = lambda1(x)](){ return a; }; 530 return lambda2(); 531 } 532 533 } 534 535 namespace test_digit_separators 536 { 537 538 constexpr auto ten_million = 100'000'000; 539 static_assert(ten_million == 100000000, ""); 540 541 } 542 543 namespace test_return_type_deduction 544 { 545 546 auto f(int& x) { return x; } 547 decltype(auto) g(int& x) { return x; } 548 549 template < typename T1, typename T2 > 550 struct is_same 551 { 552 static constexpr auto value = false; 553 }; 554 555 template < typename T > 556 struct is_same<T, T> 557 { 558 static constexpr auto value = true; 559 }; 560 561 int 562 test() 563 { 564 auto x = 0; 565 static_assert(is_same<int, decltype(f(x))>::value, ""); 566 static_assert(is_same<int&, decltype(g(x))>::value, ""); 567 return x; 568 } 569 570 } 571 572} // namespace cxx14 573 574#endif // __cplusplus >= 201402L 575 576]]) 577 578 579dnl Tests for new features in C++17 580 581m4_define([_AX_CXX_COMPILE_STDCXX_testbody_new_in_17], [[ 582 583// If the compiler admits that it is not ready for C++17, why torture it? 584// Hopefully, this will speed up the test. 585 586#ifndef __cplusplus 587 588#error "This is not a C++ compiler" 589 590#elif __cplusplus <= 201402L 591 592#error "This is not a C++17 compiler" 593 594#else 595 596#if defined(__clang__) 597 #define REALLY_CLANG 598#else 599 #if defined(__GNUC__) 600 #define REALLY_GCC 601 #endif 602#endif 603 604#include <initializer_list> 605#include <utility> 606#include <type_traits> 607 608namespace cxx17 609{ 610 611#if !defined(REALLY_CLANG) 612 namespace test_constexpr_lambdas 613 { 614 615 // TODO: test it with clang++ from git 616 617 constexpr int foo = [](){return 42;}(); 618 619 } 620#endif // !defined(REALLY_CLANG) 621 622 namespace test::nested_namespace::definitions 623 { 624 625 } 626 627 namespace test_fold_expression 628 { 629 630 template<typename... Args> 631 int multiply(Args... args) 632 { 633 return (args * ... * 1); 634 } 635 636 template<typename... Args> 637 bool all(Args... args) 638 { 639 return (args && ...); 640 } 641 642 } 643 644 namespace test_extended_static_assert 645 { 646 647 static_assert (true); 648 649 } 650 651 namespace test_auto_brace_init_list 652 { 653 654 auto foo = {5}; 655 auto bar {5}; 656 657 static_assert(std::is_same<std::initializer_list<int>, decltype(foo)>::value); 658 static_assert(std::is_same<int, decltype(bar)>::value); 659 } 660 661 namespace test_typename_in_template_template_parameter 662 { 663 664 template<template<typename> typename X> struct D; 665 666 } 667 668 namespace test_fallthrough_nodiscard_maybe_unused_attributes 669 { 670 671 int f1() 672 { 673 return 42; 674 } 675 676 [[nodiscard]] int f2() 677 { 678 [[maybe_unused]] auto unused = f1(); 679 680 switch (f1()) 681 { 682 case 17: 683 f1(); 684 [[fallthrough]]; 685 case 42: 686 f1(); 687 } 688 return f1(); 689 } 690 691 } 692 693 namespace test_extended_aggregate_initialization 694 { 695 696 struct base1 697 { 698 int b1, b2 = 42; 699 }; 700 701 struct base2 702 { 703 base2() { 704 b3 = 42; 705 } 706 int b3; 707 }; 708 709 struct derived : base1, base2 710 { 711 int d; 712 }; 713 714 derived d1 {{1, 2}, {}, 4}; // full initialization 715 derived d2 {{}, {}, 4}; // value-initialized bases 716 717 } 718 719 namespace test_general_range_based_for_loop 720 { 721 722 struct iter 723 { 724 int i; 725 726 int& operator* () 727 { 728 return i; 729 } 730 731 const int& operator* () const 732 { 733 return i; 734 } 735 736 iter& operator++() 737 { 738 ++i; 739 return *this; 740 } 741 }; 742 743 struct sentinel 744 { 745 int i; 746 }; 747 748 bool operator== (const iter& i, const sentinel& s) 749 { 750 return i.i == s.i; 751 } 752 753 bool operator!= (const iter& i, const sentinel& s) 754 { 755 return !(i == s); 756 } 757 758 struct range 759 { 760 iter begin() const 761 { 762 return {0}; 763 } 764 765 sentinel end() const 766 { 767 return {5}; 768 } 769 }; 770 771 void f() 772 { 773 range r {}; 774 775 for (auto i : r) 776 { 777 [[maybe_unused]] auto v = i; 778 } 779 } 780 781 } 782 783 namespace test_lambda_capture_asterisk_this_by_value 784 { 785 786 struct t 787 { 788 int i; 789 int foo() 790 { 791 return [*this]() 792 { 793 return i; 794 }(); 795 } 796 }; 797 798 } 799 800 namespace test_enum_class_construction 801 { 802 803 enum class byte : unsigned char 804 {}; 805 806 byte foo {42}; 807 808 } 809 810 namespace test_constexpr_if 811 { 812 813 template <bool cond> 814 int f () 815 { 816 if constexpr(cond) 817 { 818 return 13; 819 } 820 else 821 { 822 return 42; 823 } 824 } 825 826 } 827 828 namespace test_selection_statement_with_initializer 829 { 830 831 int f() 832 { 833 return 13; 834 } 835 836 int f2() 837 { 838 if (auto i = f(); i > 0) 839 { 840 return 3; 841 } 842 843 switch (auto i = f(); i + 4) 844 { 845 case 17: 846 return 2; 847 848 default: 849 return 1; 850 } 851 } 852 853 } 854 855#if !defined(REALLY_CLANG) 856 namespace test_template_argument_deduction_for_class_templates 857 { 858 859 // TODO: test it with clang++ from git 860 861 template <typename T1, typename T2> 862 struct pair 863 { 864 pair (T1 p1, T2 p2) 865 : m1 {p1}, 866 m2 {p2} 867 {} 868 869 T1 m1; 870 T2 m2; 871 }; 872 873 void f() 874 { 875 [[maybe_unused]] auto p = pair{13, 42u}; 876 } 877 878 } 879#endif // !defined(REALLY_CLANG) 880 881 namespace test_non_type_auto_template_parameters 882 { 883 884 template <auto n> 885 struct B 886 {}; 887 888 B<5> b1; 889 B<'a'> b2; 890 891 } 892 893#if !defined(REALLY_CLANG) 894 namespace test_structured_bindings 895 { 896 897 // TODO: test it with clang++ from git 898 899 int arr[2] = { 1, 2 }; 900 std::pair<int, int> pr = { 1, 2 }; 901 902 auto f1() -> int(&)[2] 903 { 904 return arr; 905 } 906 907 auto f2() -> std::pair<int, int>& 908 { 909 return pr; 910 } 911 912 struct S 913 { 914 int x1 : 2; 915 volatile double y1; 916 }; 917 918 S f3() 919 { 920 return {}; 921 } 922 923 auto [ x1, y1 ] = f1(); 924 auto& [ xr1, yr1 ] = f1(); 925 auto [ x2, y2 ] = f2(); 926 auto& [ xr2, yr2 ] = f2(); 927 const auto [ x3, y3 ] = f3(); 928 929 } 930#endif // !defined(REALLY_CLANG) 931 932#if !defined(REALLY_CLANG) 933 namespace test_exception_spec_type_system 934 { 935 936 // TODO: test it with clang++ from git 937 938 struct Good {}; 939 struct Bad {}; 940 941 void g1() noexcept; 942 void g2(); 943 944 template<typename T> 945 Bad 946 f(T*, T*); 947 948 template<typename T1, typename T2> 949 Good 950 f(T1*, T2*); 951 952 static_assert (std::is_same_v<Good, decltype(f(g1, g2))>); 953 954 } 955#endif // !defined(REALLY_CLANG) 956 957 namespace test_inline_variables 958 { 959 960 template<class T> void f(T) 961 {} 962 963 template<class T> inline T g(T) 964 { 965 return T{}; 966 } 967 968 template<> inline void f<>(int) 969 {} 970 971 template<> int g<>(int) 972 { 973 return 5; 974 } 975 976 } 977 978} // namespace cxx17 979 980#endif // __cplusplus <= 201402L 981 982]]) 983