#include #include #include #include #include #include #include #include #include #include #include // Functional programming // Function that returns a callable in the form of a lambda std::function make_adder(int x) { return ([=](int a) -> int { return x + a; }); } void do_functional() { // Lambda with no capture auto simple_lambda = [](int a) { return a + 3; }; assert(simple_lambda(5) == 8); // Capture by value int x = 5; auto by_value = [x](int a) { return a + x; }; assert(by_value(1) == 6); x = 7; // change not seen by lambda assert(by_value(1) == 6); // Also >> at end of template assert((std::is_convertible>:: value)); // Capture by reference auto by_reference = [&x](int a) { return a + x; }; assert(by_reference(1) == 8); x = 8; // change seen my lambda assert(by_reference(1) == 9); // Get a callable from a function auto add3 = make_adder(3); assert(add3(5) == 8); auto make_addr_lambda = [](int a) { return [a](int b) { return a + b; }; }; assert(make_addr_lambda(6)(8) == 14); // nullptr and {} are empty functions std::function f1 = {}; assert(!f1); std::function f2 = nullptr; assert(!f2); } // Integer types, type traits template void check_size(size_t size, bool is_signed) { assert(sizeof(T) == size); assert(std::is_signed::value == is_signed); } void do_inttypes() { // static_assert is a compile-time check static_assert(1 == sizeof(int8_t), "int8_t check"); check_size(1, true); check_size(1, false); check_size(2, true); check_size(2, false); check_size(4, true); check_size(4, false); check_size(8, true); check_size(8, false); // auto, decltype auto x = 5LL; check_size(8, true); assert((std::is_same::value)); } class A { public: static constexpr auto def_value = 5; A(int x) : x(x) { } // Constructor delegation A() : A(def_value) { } int getX() const { return x; } private: int x; }; void do_iteration() { // Initializers, foreach syntax, auto for iterators std::vector v = {1, 2, 3, 4}; assert(v.size() == 4); int sum = 0; for (auto& i: v) { sum += i; } assert(10 == sum); for (auto i = v.begin(); i != v.end(); ++i) { sum += *i; } assert(20 == sum); std::vector v2 = {A(), A(3)}; assert(5 == v2.at(0).getX()); assert(3 == v2.at(1).getX()); } // Variadic template template void variadic1(A1 const& a1) { assert(a1 == 12); } template void variadic1(A1 const& a1, A2 const& a2) { assert(a1 == a2); } template void variadic(Args... args) { variadic1(args...); } template bool pairwise_equal(A const& a, A const& b) { return (a == b); } template bool pairwise_equal(T const& a, T const& b, Rest... rest) { return pairwise_equal(a, b) && pairwise_equal(rest...); } void do_variadic() { variadic(15, 15); variadic(12); assert(pairwise_equal(5, 5, 2.0, 2.0, std::string("a"), std::string("a"))); assert(!pairwise_equal(5, 5, 2.0, 3.0)); } // deleted, default class B { public: B(int x) : x(x) { } B() : B(5) { } int getX() const { return x; } virtual ~B() = default; B(B const&) = delete; B& operator=(B const&) = delete; private: int x; }; void do_default_deleted() { B b1; assert(5 == b1.getX()); assert(std::is_copy_constructible::value); assert(!std::is_copy_constructible::value); } // smart pointers class C { public: C(int id = 0) : id(id) { incr(id); } ~C() { decr(id); } C(C const& rhs) : C(rhs.id) { } C& operator=(C const& rhs) { if (&rhs != this) { decr(id); id = rhs.id; incr(id); } return *this; } static void check(size_t size, int v, int count) { assert(m.size() == size); auto p = m.find(v); if (p != m.end()) { assert(p->second == count); } } private: void incr(int i) { ++m[i]; } void decr(int i) { if (--m[i] == 0) { m.erase(i); } } static std::map m; int id; }; std::map C::m; std::shared_ptr make_c(int id) { return std::make_shared(id); } std::shared_ptr make_c_array(std::vector const& is) { auto p = std::shared_ptr(new C[is.size()], std::default_delete()); C* pp = p.get(); for (size_t i = 0; i < is.size(); ++i) { pp[i] = C(is.at(i)); } return p; } void do_smart_pointers() { auto p1 = make_c(1); C::check(1, 1, 1); auto p2 = make_c_array({2, 3, 4, 5}); for (auto i: {1, 2, 3, 4, 5}) { C::check(5, i, 1); } { C::check(5, 1, 1); C c3(*p1); C::check(5, 1, 2); } C::check(5, 1, 1); p1 = nullptr; C::check(4, 1, 0); p2 = nullptr; C::check(0, 0, 0); { std::unique_ptr p3(new C(6)); C::check(1, 6, 1); } C::check(0, 0, 0); } // Regular expressions void do_regex() { // Basic match/search. Match matches whole string; search searches // within string. Use std::smatch for matching std::string and // std::cmatch for matching char const*. std::regex expr1("([0-9]+)"); std::regex expr2("([0-9]+)\\s*([a-z]+)[[:space:]]*([0-9]+)"); std::string str1("one 234 fifth 678 nine"); std::string str2("234 five 678 nine"); std::string str3("one 234 five 678"); std::string str4("234"); std::string str5("234 five 678"); std::smatch match1; assert(!std::regex_match(str1, match1, expr1)); assert(!std::regex_match(str2, match1, expr1)); assert(!std::regex_match(str3, match1, expr1)); assert(std::regex_match(str4, match1, expr1)); assert(match1[0].first == match1[1].first); assert(match1[0].second == match1[1].second); std::string s; s.assign(match1[1].first, match1[1].second); assert("234" == s); assert(s == match1[1].str()); assert(std::regex_match(str5, match1, expr2)); assert("234 five 678" == match1[0].str()); assert("234" == match1[1].str()); assert("five" == match1[2].str()); assert("678" == match1[3].str()); assert(std::regex_search(str1, match1, expr2)); assert("234 fifth 678" == match1[0].str()); assert("234" == match1[1].str()); assert("fifth" == match1[2].str()); assert("678" == match1[3].str()); // Iterator std::regex expr3("[[:digit:]]+"); std::string str6 = "asdf234erasdf9453.kgdl423asdf"; std::sregex_iterator m1(str6.begin(), str6.end(), expr3); std::sregex_iterator m2; s.clear(); for (std::sregex_iterator iter = m1; iter != m2; ++iter) { std::smatch const& match2 = *iter; s += match2[0].str() + "|"; } assert("234|9453|423|" == s); // Submatches std::regex expr4("(?:(asdf)|(qwer))"); char const* str7 = "0asdf1qwer2"; std::cregex_iterator m3(str7, str7 + std::strlen(str7), expr4); assert("asdf" == (*m3)[0].str()); assert((*m3)[1].matched); assert(!(*m3)[2].matched); ++m3; assert("qwer" == (*m3)[0].str()); assert(!(*m3)[1].matched); assert((*m3)[2].matched); } static long operator""_x(char const* v) { return strtol(v, nullptr, 16); } static std::string operator""_y(char const* v, size_t len) { return "y" + std::string(v, len) + "y"; } void do_user_defined_literals() { assert(10_x == 16); // operator""_x("10") assert("abc"_y == "yabcy"); // operator""_y("abc", 3) // Raw literals. Optional matching label before and after () // allows embedding something that looks like the default end // delimiter in the string. assert(R"(abc)"_y == "yabcy"); // This construct does not work in MSVC as of version 2019. // assert(R"x(a)"bc)x"_y == "ya)\"bcy"); } int main() { do_functional(); do_inttypes(); do_iteration(); do_variadic(); do_default_deleted(); do_smart_pointers(); do_regex(); do_user_defined_literals(); std::cout << "assertions passed\n"; return 0; }