initializer_list
template< class T >
class initializer_list;
https://en.cppreference.com/w/cpp/utility/initializer_list
size | returns the number of elements in the initializer list (public member function) |
begin | returns a pointer to the first element (public member function) |
end | returns a pointer to one past the last element (public member function) |
#include <iostream>
#include <vector>
#include <initializer_list>
template <class T>
struct S {
std::vector<T> v;
S(std::initializer_list<T> l) : v(l) {
std::cout << "constructed with a " << l.size() << "-element list\n";
}
void append(std::initializer_list<T> l) {
v.insert(v.end(), l.begin(), l.end());
}
std::pair<const T*, std::size_t> c_arr() const {
return {&v[0], v.size()}; // copy list-initialization in return statement
// this is NOT a use of std::initializer_list
}
};
template <typename T>
void templated_fn(T) {}
int main()
{
S<int> s = {1, 2, 3, 4, 5}; // copy list-initialization
s.append({6, 7, 8}); // list-initialization in function call
std::cout << "The vector size is now " << s.c_arr().second << " ints:\n";
for (auto n : s.v)
std::cout << n << ' ';
std::cout << '\n';
std::cout << "Range-for over brace-init-list: \n";
for (int x : {-1, -2, -3}) // the rule for auto makes this ranged-for work
std::cout << x << ' ';
std::cout << '\n';
auto al = {10, 11, 12}; // special rule for auto
std::cout << "The list bound to auto has size() = " << al.size() << '\n';
// templated_fn({1, 2, 3}); // compiler error! "{1, 2, 3}" is not an expression,
// it has no type, and so T cannot be deduced
templated_fn<std::initializer_list<int>>({1, 2, 3}); // OK
templated_fn<std::vector<int>>({1, 2, 3}); // also OK
}
using namespace std;
template<class T>
class A{
public:
template <std::size_t N>
A(const T (&t)[N]){//or &&t
cout<< t[0];
cout<<N;
}
};
int main(int argc,char* argv[]){
int arr[]={1,2};
A a({1,2});
return 0;
}
tuple
pair is like tuple but with two elements first and second
https://en.cppreference.com/w/cpp/utility/tuple
#include <tuple>
#include <iostream>
#include <string>
#include <stdexcept>
std::tuple<double, char, std::string> get_student(int id)
{
if (id == 0) return std::make_tuple(3.8, 'A', "Lisa Simpson");
if (id == 1) return std::make_tuple(2.9, 'C', "Milhouse Van Houten");
if (id == 2) return std::make_tuple(1.7, 'D', "Ralph Wiggum");
throw std::invalid_argument("id");
}
int main()
{
auto student0 = get_student(0);
std::cout << "ID: 0, "
<< "GPA: " << std::get<0>(student0) << ", "
<< "grade: " << std::get<1>(student0) << ", "
<< "name: " << std::get<2>(student0) << '\n';
double gpa1;
char grade1;
std::string name1;
std::tie(gpa1, grade1, name1) = get_student(1);
std::cout << "ID: 1, "
<< "GPA: " << gpa1 << ", "
<< "grade: " << grade1 << ", "
<< "name: " << name1 << '\n';
// C++17 structured binding:
auto [ gpa2, grade2, name2 ] = get_student(2);
std::cout << "ID: 2, "
<< "GPA: " << gpa2 << ", "
<< "grade: " << grade2 << ", "
<< "name: " << name2 << '\n';
}
std::tuple<int, int> foo_tuple()
{
return {1, -1}; // Error until N4387
return std::tuple<int, int>{1, -1}; // Always works
return std::make_tuple(1, -1); // Always works
}
apply
int add(int first, int second) { return first + second; }
template<typename T>
T add_generic(T first, T second) { return first + second; }
auto add_lambda = [](auto first, auto second) { return first + second; };
template<typename... Ts>
std::ostream& operator<<(std::ostream& os, std::tuple<Ts...> const& theTuple)
{
std::apply
(
[&os](Ts const&... tupleArgs)
{
os << '[';
std::size_t n{0};
((os << tupleArgs << (++n != sizeof...(Ts) ? ", " : "")), ...);
os << ']';
}, theTuple
);
return os;
}
int main()
{
// OK
std::cout << std::apply(add, std::pair(1, 2)) << '\n';
// Error: can't deduce the function type
// std::cout << std::apply(add_generic, std::make_pair(2.0f, 3.0f)) << '\n';
// OK
std::cout << std::apply(add_lambda, std::pair(2.0f, 3.0f)) << '\n';
// advanced example
std::tuple myTuple(25, "Hello", 9.31f, 'c');
std::cout << myTuple << '\n';
}
move
std::move
is used to indicate that an object t
may be “moved from”, i.e. allowing the efficient transfer of resources from t
to another object.
In particular, std::move
produces an xvalue expression that identifies its argument t
. It is exactly equivalent to a static_cast to an rvalue reference type.
#include <iostream>
#include <utility>
#include <vector>
#include <string>
int main()
{
std::string str = "Hello";
std::vector<std::string> v;
// uses the push_back(const T&) overload, which means
// we'll incur the cost of copying str
v.push_back(str);
std::cout << "After copy, str is \"" << str << "\"\n";
// uses the rvalue reference push_back(T&&) overload,
// which means no strings will be copied; instead, the contents
// of str will be moved into the vector. This is less
// expensive, but also means str might now be empty.
v.push_back(std::move(str));
std::cout << "After move, str is \"" << str << "\"\n";
std::cout << "The contents of the vector are \"" << v[0]
<< "\", \"" << v[1] << "\"\n";
}
After copy, str is "Hello" After move, str is "" The contents of the vector are "Hello", "Hello"
forward
template<class T>
void wrapper(T&& arg)
{
// arg is always lvalue
foo(std::forward<T>(arg)); // Forward as lvalue or as rvalue, depending on T
}
struct Arg
{
int i = 1;
int get() && { return i; } // call to this overload is rvalue
int& get() & { return i; } // call to this overload is lvalue
};
#include <iostream>
#include <memory>
#include <utility>
struct A {
A(int&& n) { std::cout << "rvalue overload, n=" << n << "\n"; }
A(int& n) { std::cout << "lvalue overload, n=" << n << "\n"; }
};
class B {
public:
template<class T1, class T2, class T3>
B(T1&& t1, T2&& t2, T3&& t3) :
a1_{std::forward<T1>(t1)},
a2_{std::forward<T2>(t2)},
a3_{std::forward<T3>(t3)}
{
}
private:
A a1_, a2_, a3_;
};
template<class T, class U>
std::unique_ptr<T> make_unique1(U&& u)
{
return std::unique_ptr<T>(new T(std::forward<U>(u)));
}
template<class T, class... U>
std::unique_ptr<T> make_unique2(U&&... u)
{
return std::unique_ptr<T>(new T(std::forward<U>(u)...));
}
int main()
{
auto p1 = make_unique1<A>(2); // rvalue
int i = 1;
auto p2 = make_unique1<A>(i); // lvalue
std::cout << "B\n";
auto t = make_unique2<B>(2, i, 3);
}
rvalue overload, n=2 lvalue overload, n=1 B rvalue overload, n=2 lvalue overload, n=1 rvalue overload, n=3
exchange
template<class T, class U = T>
constexpr // since C++20
T exchange(T& obj, U&& new_value)
{
T old_value = std::move(obj);
obj = std::forward<U>(new_value);
return old_value;
}
swap
int main()
{
int a = 5, b = 3;
// before
std::cout << a << ' ' << b << '\n';
std::swap(a,b);
// after
std::cout << a << ' ' << b << '\n';
}
bitset
set,reset,flip,size,all,any,none ~^|&
https://en.cppreference.com/w/cpp/utility/bitset
#include <bitset>
int main()
{
std::bitset<8> b1(42);
for (std::size_t i = 0; i < b1.size(); ++i) {
std::cout << "b1[" << i << "]: " << b1[i] << '\n';
}
b1[0] = true; // modifies the first bit through bitset::reference
std::cout << "After setting bit 0, the bitset holds " << b1 << '\n';
}
type_traits
https://en.cppreference.com/w/cpp/header/type_traits
Composite type categories | Primary type category |
---|---|
is_arithmetic | is_floating_point or is_integral |
is_fundamental | is_arithmetic or is_void |
is_object | is_arithmetic or is_enum or is_pointer or is_member_pointer |
is_reference | is_lvalue_reference or is_rvalue_reference |
is_compound | complement of is_fundamental |
is_member_pointer | is_member_object_pointer or is_member_function_pointer |
template class Base, class Derived> | Checks if Derived is derived from Base . |
struct is_base_of | |
template <class From, class To> | Checks if From can be converted to To . |
struct is_convertible | |
template <class T, class U> | Checks if the types T and U are the same. |
struct is_same |
#include <type_traits>
using std::cout;
cout << std::is_void<void>::value; // true
cout << std::is_integral<short>::value; // true
cout << std::is_floating_point<double>::value; // true
cout << std::is_array<int [] >::value; // true
cout << std::is_pointer<int*>::value; // true
cout << std::is_reference<int&>::value; // true
struct A{
int a;
int f(int){ return 2011; }
};
cout << std::is_member_object_pointer<int A::*>::value; // true
cout << std::is_member_function_pointer<int (A::*)(int)>::value; // true
enum E{
e= 1,
};
cout << std::is_enum<E>::value; // true
union U{
int u;
};
cout << std::is_union<U>::value; // true
cout << std::is_class<std::string>::value; // true
cout << std::is_function<int * (double)>::value; // true
cout << std::is_lvalue_reference<int&>::value; // true
cout << std::is_rvalue_reference<int&&>::value; // true
cout << is_const<int>::value; // false
cout << is_const<const int>::value; // true
cout << is_const<add_const<int>::type>::value; // true
typedef add_const<int>::type myConstInt;
cout << is_const<myConstInt>::value; //true
typedef const int myConstInt2;
cout << is_same<myConstInt, myConstInt2>::value; // true
cout << is_same<int, remove_const<add_const<int>::type>::type>::value; // true
cout << is_same<const int, add_const<add_const<int>::type>::type>::value; // true
functional
https://en.cppreference.com/w/cpp/header/functional
...
#include <functional>
...
// for placehoder _1 and _2
using namespace std::placeholders; f
using std::bind;
using std::function
...
double divMe(double a, double b){ return a/b; };
function < double(double, double) > myDiv1= bind(divMe, _1, _2);
function < double(double) > myDiv2= bind(divMe, 2000, _1);
divMe(2000, 10) == myDiv1(2000, 10) == myDiv2(10);
#include <functional>
...
using std::make_pair;
using std::map;
map<const char, std::function<double(double, double)>> tab;
tab.insert(make_pair('+', [](double a, double b){ return a + b; }));
tab.insert(make_pair('-', [](double a, double b){ return a - b; }));
tab.insert(make_pair('*', [](double a, double b){ return a * b; }));
tab.insert(make_pair('/', [](double a, double b){ return a / b; }));
std::cout << tab['+'](3.5, 4.5); // 8
std::cout << tab['-'](3.5, 4.5); // -1
std::cout << tab['*'](3.5, 4.5); // 15.75
std::cout << tab['/'](3.5, 4.5); // 0.777778
Function type | Return type | Type of the arguments |
---|---|---|
double(double, double) | double | double |
int() | int | |
double(int, double) | double | int, double |
void() |
std::variant
std::variant
is a type-safe union. An instance of std::variant
has a value from one of its types. The type must not be a reference, array or void
.
#include <variant>
...
std::variant<int, float> v, w;
v = 12; // v contains int
int i = std::get<int>(v);
w = std::get<int>(v);
w = std::get<0>(v); // same effect as the previous line
w = v; // same effect as the previous line
// std::get<double>(v); // error: no double in [int, float]
// std::get<3>(v); // error: valid index values are 0 and 1
try{
std::get<float>(w); // w contains int, not float: will throw
}
catch (std::bad_variant_access&) {}
std::variant<std::string> v("abc"); // converting constructor must be unambiguous
v = "def"; // converting assignment must be unambiguous
optional
can have value or empty
#include <optional>
std::optional<int> getFirst(const std::vector<int>& vec){
if (!vec.empty()) return std::optional<int>(vec[0]);
else return std::optional<int>();
}
...
std::vector<int> myVec{1, 2, 3};
std::vector<int> myEmptyVec;
auto myInt= getFirst(myVec);
if (myInt){
std::cout << *myInt << std::endl; // 1
std::cout << myInt.value() << std::endl; // 1
std::cout << myInt.value_or(2017) << std::endl; // 1
}
auto myEmptyInt= getFirst(myEmptyVec);
if (!myEmptyInt){
std::cout << myEmptyInt.value_or(2017) << std::endl; // 2017
}
std::any
std::any
is a type-safe container for single values of any type which is copy-constructible.
#include <algorithm>
#include <any>
#include <iostream>
#include <string>
#include <vector>
class Star
{
std::string name;
int id;
public:
Star(std::string name, int id) : name { name }, id { id }
{
std::cout << "Star::Star(string, int)\n";
}
void print() const
{
std::cout << "Star{ \"" << name << "\" : " << id << " };\n";
}
};
auto main() -> int
{
std::any celestial;
// (1) emplace( Args&&... args );
celestial.emplace<Star>("Procyon", 2943);
const auto* star = std::any_cast<Star>(&celestial);
star->print();
std::any av;
// (2) emplace( std::initializer_list<U> il, Args&&... args );
av.emplace<std::vector<char>>({ 'C', '+', '+', '1', '7' } /* no args */ );
std::cout << av.type().name() << '\n';
const auto* va = std::any_cast<std::vector<char>>(&av);
std::for_each(va->cbegin(), va->cend(), [](char const& c) { std::cout << c; });
std::cout << '\n';
}
#include <any>
struct MyClass{};
...
std::vector<std::any> anyVec{true, 2017, std::string("test"), 3.14, MyClass()};
std::cout << std::any_cast<bool>(anyVec[0]); // true
int myInt= std::any_cast<int>(anyVec[1]);
std::cout << myInt << std::endl; // 2017
std::cout << anyVec[0].type().name(); // b
std::cout << anyVec[1].type().name(); // i
any a=any(12);
a.emplace<B>(B());
cout<<a.type().name();//1B