/** @file @brief C++17 @defgroup CPP17 C++17 examples https://en.wikipedia.org/wiki/C++17 https://github.com/AnthonyCalandra/modern-cpp-features/blob/master/CPP17.md https://en.cppreference.com/w/cpp/language/history/17 @{ */ static_assert(__cplusplus == 201703); #include using namespace std; /** @defgroup templ17 Template https://en.cppreference.com/w/cpp/language/templates @{ */ /** @defgroup template_argument_deduction Template argument deduction [template_argument_deduction](https://en.cppreference.com/w/cpp/language/template_argument_deduction) [class_template_argument_deduction](https://en.cppreference.com/w/cpp/language/class_template_argument_deduction) @{ */ /// @brief pair p(1, 2.3); constexpr pair deducted_pair(1, 2.3); static_assert(deducted_pair.second == 2.3); /// @brief auto t = make_tuple(4, 3, 2.5); constexpr tuple deducted_tuple(4, 2, 2.5); static_assert(get<2>(deducted_tuple) == 2.5); /// @brief template with type float by default template struct template_struct { T val; template_struct() : val() { } template_struct(T val) : val(val) { } }; /// @brief deducted \ template_struct template_arg_deduction { 1 }; #if __cpp_deduction_guides > 201611 /// @brief deducted \ template_struct template_default_arg_deduction; #endif vector int_vector = { 1, 2, 3, 4 }; /// [deduction_guides](https://en.cppreference.com/w/cpp/container/deque/deduction_guides) /// @brief deduced deque\ deque deduction_guide1_queue(int_vector.begin(), int_vector.end()); /// @brief deduced deque\ :: iterator\> deque deduction_guide2_queue { int_vector.cbegin(), int_vector.cend() }; /// [deduction_guides](https://en.cppreference.com/w/cpp/container/array/deduction_guides) array deduction_guide_array { 1, 2, 3, 4 }; /// [deduction_guides](https://en.cppreference.com/w/cpp/container/vector/deduction_guides) /// @brief deduced vector\ vector deduction_guide1_vector(int_vector.begin(), int_vector.end()); /// @brief deduced vector\ :: iterator\> vector deduction_guide2_vector { int_vector.begin(), int_vector.end() }; /** @} template_argument_deduction */ void deduction_guides_17() { assert(deduction_guide1_queue[0] == 1); assert(*deduction_guide2_queue[0] == 1); assert(deduction_guide1_vector[0] == 1); assert(*deduction_guide2_vector[0] == 1); } /** @defgroup template_parameters Template parameters [template_parameters](https://en.cppreference.com/w/cpp/language/template_parameters) @{ */ template struct B { /* ... */ }; B<5> b1; // OK: non-type template parameter type is int B<'a'> b2; // Error: // B<2.5> b3; tuple foo_tuple() { // return make_tuple(1, -1); return { 1, -1 }; } template struct my_integer_sequence { }; /// @brief auto seq = integer_sequence(); auto seq = my_integer_sequence<0, 1, 2>(); /** @} template_parameters @} templ17 @defgroup lambda17 Lambda @{ */ /** @defgroup constexpr_lambda Constexpr lambda [lambda](https://en.cppreference.com/w/cpp/language/lambda) [lambda-expressions-constexpr](https://docs.microsoft.com/en-us/cpp/cpp/lambda-expressions-constexpr) @{ */ // explicit constexpr auto identity = [](int n) constexpr { return n; }; static_assert(identity(1) == 1); // lambda with auto argument actually is a template // implicit auto constexpr: auto can_be_constexpr1 = [](auto a) { return a; }; auto can_be_constexpr2 = [](int (*fp)(int), auto a) { return fp(a); }; static_assert(can_be_constexpr2(can_be_constexpr1, 3) == 3); // error: non-constant condition for static assertion // static int i=0; // static_assert(can_be_constexpr2(can_be_constexpr1, i) == 0); auto non_const = [](auto a) { static int s; return a; }; // error: no specialization can be constexpr because of s // static_assert(can_be_constexpr(non_const, 3)==3); constexpr int const_inc(int n) { return [n] { return n + 1; }(); } constexpr int (*inc)(int) = const_inc; static_assert(const_inc(1) == 2); /** @} constexpr_lambda @defgroup lcbv Lambda capture this by value [Lambda capture](https://en.cppreference.com/w/cpp/language/lambda#Lambda_capture) @{ */ void capture_this_by_value() { struct capture_value_o { int value { 1 }; auto get_value_copy() { return [*this] { return value; }; } }; capture_value_o mo; auto val = mo.get_value_copy(); mo.value = 2; assert(val() == 1); } void lambda_17() { assert(can_be_constexpr1(2) == 2); int i = 3; assert(can_be_constexpr2(can_be_constexpr1, 3) == 3); non_const(1); capture_this_by_value(); } /** @} lcbv @} lambda17 @defgroup threads17 Threads [threads](https://en.cppreference.com/w/cpp/thread) @{ */ /** [shared_lock](https://en.cppreference.com/w/cpp/thread/shared_lock) [shared_mutex](https://en.cppreference.com/w/cpp/thread/shared_mutex) [scoped_lock](https://en.cppreference.com/w/cpp/thread/scoped_lock) */ void threads_17() { shared_mutex m; shared_lock lock(m); mutex mt[2]; thread t2; { scoped_lock l1(mt[0], mt[1]); t2 = thread([&mt] { scoped_lock l2(mt[0], mt[1]); }); } t2.join(); } /// @} threads17 /** @defgroup lang17 Language @brief [language](https://en.cppreference.com/w/cpp/language) @{ */ void references_17() { static_assert(is_reference_v); // L-value: static_assert(is_lvalue_reference_v); // R-value static_assert(is_rvalue_reference_v); } /** @defgroup folding Folding @brief [fold](https://en.cppreference.com/w/cpp/language/fold) @{ */ template constexpr bool folding_and(Args... args) { return (true && ... && args); } template constexpr auto folding_sum(Args... args) { return (... + args); } void folding_demo() { static_assert(!folding_and(true, false, true)); static_assert(folding_sum(1.0, 2.0f, 3) == 6.0); } /** @} folding @defgroup nn Qualified nested namespace @brief [namespace](https://en.cppreference.com/w/cpp/language/namespace) http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4026.html @{ */ /// Before: namespace outer_namespace { namespace nested_namespace { } } namespace outer_namespace::qualified_nested_namespace { int in_qualified_nested_namespace; } /** @} nn @defgroup sb Structured bindings [structured binding](https://en.cppreference.com/w/cpp/language/structured_binding) @{ */ static_assert(__cpp_structured_bindings); void structured_bindings() { int a[2] = { 1, 2 }; auto [a0, a1] = a; // a0_ref = &a; a0_ref = &a; auto& [a0_ref, a1_ref] = a; float x {}; char y {}; int z {}; unordered_map mapping { { "a", 1 }, { "b", 2 }, { "c", 3 }, }; for (const auto& [key, value] : mapping) { // Do something with key and value } // tuple tpl(x,move(y),z); // const auto& [a,b,c] = tpl; // https://en.cppreference.com/w/cpp/language/structured_binding auto [min, max] = minmax({ 3, 2, 1 }); assert(min == 1); assert(max == 3); } /// @} sb /** Variable declaration in conditionals Specs: [if](https://en.cppreference.com/w/cpp/language/if), [switch](https://en.cppreference.com/w/cpp/language/switch) */ void conditional_with_init() { if (auto a = true) { }; switch (int a = 10) { } } /** @defgroup attr New attributes @brief [fallthrough](https://en.cppreference.com/w/cpp/language/attributes/fallthrough), [nodiscard](https://en.cppreference.com/w/cpp/language/attributes/nodiscard), [maybe_unused](https://en.cppreference.com/w/cpp/language/attributes/maybe_unused) @{ */ // Will warn if return of foo() is ignored [[nodiscard]] int foo() { return 1; } void test_attr() { int a { 1 }; switch (a) { // Indicates that falling through on case 1 is intentional case 1: [[fallthrough]]; case 2: // Indicates that b might be unused, such as on production builds [[maybe_unused]] int b = foo(); assert(b > 0); break; } } /// @} /** @brief [if](https://en.cppreference.com/w/cpp/language/if) */ constexpr int const_if() { if constexpr (true) return 1; } static_assert(const_if()); /** Character literal @brief [character_literal](https://en.cppreference.com/w/cpp/language/character_literal) */ static char char_u8 = u8'x'; /** Direct list initialization of [enum](https://en.cppreference.com/w/cpp/language/enum)s [floating_literal](https://en.cppreference.com/w/cpp/language/floating_literal) [invoke](https://en.cppreference.com/w/cpp/utility/functional/invoke) */ void types_17() { enum byte_e : unsigned char { }; static byte_e b { 123 }; floating_literal: static_assert(is_integral_v); static_assert(__cpp_hex_float); double hex_double = 0x1.2p3; assert(hex_double == 9.0); static_assert(is_invocable::value); static_assert(is_invocable::value); static_assert(is_invocable_r::value); static_assert(is_invocable_r::value); static_assert(negation_v>); auto inc = [](int a) -> int { return a + 1; }; static_assert(is_invocable_r::value); static_assert(__cpp_lib_invoke); assert(invoke(inc, 2) == 3); } /// [language](https://en.cppreference.com/w/cpp/language) void lang_17() { references_17(); folding_demo(); structured_bindings(); conditional_with_init(); test_attr(); types_17(); /// https://en.cppreference.com/w/cpp/language/range-for map mymap; for (auto&& [first, second] : mymap) { // use first and second } } /** @} lang17 @defgroup lib17 Library @{ */ void map_demo() { /// @brief https://en.cppreference.com/w/cpp/container/map/extract map m { { 1, "mango" }, { 2, "papaya" }, { 3, "guava" } }; auto nh = m.extract(2); nh.key() = 4; /// @brief https://en.cppreference.com/w/cpp/container/map/insert m.insert(move(nh)); // m == {{1, "mango"}, {3, "guava"}, {4, "papaya"}} /// @brief https://en.cppreference.com/w/cpp/container/map/merge set src { 1, 3, 5 }; set dst { 2, 4, 5 }; dst.merge(src); assert(size(dst) == 5); } /** [variant](https://en.cppreference.com/w/cpp/utility/variant) [visit](https://en.cppreference.com/w/cpp/utility/variant/visit) */ void variant_demo() { variant v, w; v = 12; // v contains int int i = get(v); w = get(v); w = get<0>(v); // same effect as the previous line w = v; // same effect as the previous line // get(v); // error: no double in [int, float] // get<3>(v); // error: valid index values are 0 and 1 try { get(w); // w contains int, not float: will throw } catch (const bad_variant_access&) { } using namespace literals; variant x("abc"); // converting constructors work when unambiguous x = "def"; // converting assignment also works when unambiguous variant y("abc"); // casts to void const * when passed a char const * assert(holds_alternative(y)); y = "xyz"s; assert(holds_alternative(y)); auto inc = [](int a) -> int { return a + 1; }; assert(visit(inc, (variant)1) == 2); } void optional_demo() { optional i = make_optional(1); assert(i.has_value()); assert(i.value() == 1); i = nullopt; assert(i.value_or(2) == 2); } void clamp_demo() { static_assert(__cpp_lib_clamp); /// clamp(x, low, high) == x < low ? low : x > high ? high : x; assert(clamp(0, 1, 3) == 1); assert(clamp(2, 1, 3) == 2); assert(clamp(4, 1, 3) == 3); } void dynamic_memory_17() { int d[2] = { 10, 11 }; unique_ptr u1(d); assert(u1.get()[0] == 10); // C++11 assert(u1[1] == 11); assert((bool)u1); u1.release(); const shared_ptr s1 { 0 }; // cout << s1.element_type.name() << endl; // cout << typeid(s1.weak_type).name() << endl; assert(typeid(reinterpret_pointer_cast>(s1)).name() == string("St10shared_ptrIS_IiEE")); vector s = { 5, 7, 4, 2, 8, 6, 1, 9, 0, 3 }; // https://en.cppreference.com/w/cpp/numeric/valarray/deduction_guides int a[] = { 1, 2, 3 }; valarray va(a, 3); // uses explicit deduction guide static_assert(is_integral_v::type>); } void string_view_demo() { static_assert(__cpp_lib_string_view); string s = "abcd"; string_view v = s; assert(v.data() == s.c_str()); assert(v.substr(1, 2).data() >= s.c_str()); assert(v.substr(1, 2).data() <= s.c_str() + s.length()); } /// @} lib17 /** @defgroup other17 Other @{ */ /// [inline](https://en.cppreference.com/w/cpp/language/inline) inline int inline_var; /** @} other17 */ int main() { deduction_guides_17(); lang_17(); lambda_17(); threads_17(); map_demo(); variant_demo(); optional_demo(); clamp_demo(); dynamic_memory_17(); string_view_demo(); } /** @} CPP17 */