template <typename T> using StringMap = std::map<std::string, T>;
StringMap<int> map; // map is a std::map<std::string, int>
Compile-Time if
Consider writing an operation that can use one of two operations slowAndSafe(T) or simpleAndFast(T).
1 2 3 4 5 6 7
template<typename T> voidupdate(T &target){ ifconstexpr(std::is_pod<T>::value) simpleAndFast(target); // for "plain old data" else slowAndSafe(target); }
Variadic Templates
1 2 3 4 5 6
template <typename T, typename... Tail> voidprint(T head, Tail... tail){ // what we do for each argument, e.g., std::cout << head << ' '; ifconstexpr(sizeof...(tail) > 0)print(tail...); }
Essential Operations
1 2 3 4 5 6 7 8 9 10 11
classX { public: X(Sometype); // "ordinary constructor": create an object X(); // default constructor X(const X &); // copy constructor X(X &&); // move constructor X &operator=(const X &); // copy assignment: clean up target and copy X &operator=(X &&); // move assignment: clean up target and move ~X(); // destructor: clean up // ... };
use = default to generate default constructor, use = delete to delete operations.
Conversions
use explicit to eliminate implicit conversions.
1 2 3 4
classVector { public: explicitVector(int); // no implicit conversion from int to Vector };
Member Initializers
When a data member of a class is defined, we can supply a default initializer called a default member initializer.
1 2 3 4
structPoint { double x = 0; double y = 0; };
String
Literals
1 2 3 4 5 6 7 8
#include<string>
usingnamespacestd::literals::string_literals;
intmain(){ auto s = "123"s; // std::string return0; }
String Views
a string_view is basically a (pointer, length) pair denoting a sequence of characters:
std::stringcat(std::string_view sv1, std::string_view sv2){ std::stringres(sv1.length() + sv2.length(), '\0'); char *p = res.data(); for (char c : sv1) // one way to copy *p++ = c; std::copy(sv2.begin(), sv2.end(), p); // another way return res; }
intmain(){ std::string king = "Harold"; auto s1 = cat(king, "William"); // string and const char * auto s2 = cat(king, king); // string and string auto s3 = cat("Edward", "Stephen"sv); // const char *and string_view auto s4 = cat("Canute"sv, king); auto s5 = cat({&king[0], 2}, "Henry"sv); // HaHenry auto s6 = cat({&king[0], 2}, {&king[2], 4}); // Harold return0; }
Utilities
unique_ptr and shared_ptr
1 2
std::unique_ptr<int> a = std::make_unique<int>(1); auto p = std::make_shared<int>(1);
move
1 2 3 4 5 6
template <typename T> voidswap(T &a, T &b){ T tmp{std::move(a)}; a = std::move(b); b = std::move(tmp); }
intmain(){ usingnamespacestd::chrono_literals; auto func = []() { double ret = 0; for (int i = 0; i < 10000000; i++) ret += sin(i); return ret; }; auto start = std::chrono::high_resolution_clock::now(); std::cout << func() << std::endl; auto end = std::chrono::high_resolution_clock::now(); std::cout << std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count() << "ms\n"; start = std::chrono::high_resolution_clock::now(); std::this_thread::sleep_for(10ms + 33us); end = std::chrono::high_resolution_clock::now(); std::cout << std::chrono::duration_cast<std::chrono::microseconds>(end - start).count() << "us\n"; }
mem_fn
Function template std::mem_fn generates wrapper objects for pointers to members, which can store, copy, and invoke a pointer to member. Both references and pointers (including smart pointers) to an object can be used when invoking a std::mem_fn.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
#include<functional> #include<iostream>
structFoo { voidgreet(){ std::cout << "Hello, world.\n"; } voidnumber(int i){ std::cout << "number: " << i << '\n'; } int data = 7; };
intmain(){ Foo f; auto greet = std::mem_fn(&Foo::greet); greet(f); auto print = std::mem_fn(&Foo::number); print(f, 42); auto data = std::mem_fn(&Foo::data); std::cout << "data: " << data(f) << '\n'; }
enable_if
1 2 3 4 5 6 7 8 9
#include<functional> #include<iostream>
template <typename T> structSmartPointer { T &operator*(); std::enable_if<std::is_class_v<T>(), T &> operator->(); // is defined if and only if T is a class };