/**
@file
@brief C++11
@defgroup CPP11 C++11 examples
https://en.wikipedia.org/wiki/C++11
https://github.com/AnthonyCalandra/modern-cpp-features/blob/master/CPP11.md
@{
*/
static_assert(__cplusplus == 201103, "");
#include
#include
#include
#if __has_include()
#include
#endif
using namespace std;
/**
@defgroup lang11 Language
@{
*/
void types_11()
{
static_assert(__cpp_decltype, "");
int a;
// https://en.cppreference.com/w/cpp/header/type_traits
decltype(a) b; // https://en.cppreference.com/w/cpp/language/decltype
assert((is_same::value));
assert((!is_same::value));
assert((is_same::value));
assert((is_same::value));
assert(is_integral::value);
assert(is_integral::value);
assert(!is_integral::value);
assert(is_pointer::value);
assert(sizeof(long long) >= 8);
enum class Number { zero,
tree = 3,
four };
Number n = Number::zero;
assert(static_cast(n) == 0);
assert(is_enum());
}
/// [unique_ptr](https://en.cppreference.com/w/cpp/memory/unique_ptr)
void unique_pounter()
{
int d = 0;
unique_ptr u1;
assert(!u1);
u1.reset(&d);
assert(u1);
*u1 = 1;
assert(d == 1);
unique_ptr u2;
// u2 = u1; - prohibited
int* p1 = u1.get();
u2 = move(u1); // [move](https://en.cppreference.com/w/cpp/utility/move)
assert(u2.get() == p1);
assert(u2);
assert(!u1);
assert(u2.get() == &d);
// must release because d is local
u2.release();
u2.reset(new int(10));
assert(*u2 == 10);
u2.reset(); // deletes int(10)
assert(u2 == nullptr); // [nullptr](https://en.cppreference.com/w/cpp/language/nullptr)
assert(!u2);
}
/// [shared_ptr](https://en.cppreference.com/w/cpp/memory/shared_ptr)
void shared_pointer()
{
shared_ptr s1;
assert(!s1);
assert(!s1.use_count());
auto s2 = make_shared(1);
assert(s2.use_count() == 1);
s1 = s2;
assert(s1.use_count() == 2);
*s1 = 2;
assert(*s1 == *s1.get());
assert(*s2 == 2);
s2 = nullptr; // like s2.reset();
assert(s1.use_count() == 1);
assert(!s2.use_count());
}
/// [weak_ptr](https://en.cppreference.com/w/cpp/memory/weak_ptr)
void weak_pointer()
{
weak_ptr wp;
assert(!wp.lock());
assert(!wp.use_count());
auto sp = make_shared(1);
wp = sp;
assert(*wp.lock() == 1);
}
/**
[new](https://en.cppreference.com/w/cpp/memory/new/operator_new),
[delete](https://en.cppreference.com/w/cpp/memory/new/operator_delete)
*/
void dynamic_memory_11()
{
auto a = new int[3] { 1, 2, 3 };
assert(a[2] == 3);
delete a;
auto as = new string[3] { "1", "2", "3" };
assert(as[2] == "3");
delete[] as; // calls destructors for all members
unique_pounter();
shared_pointer();
weak_pointer();
}
/// func_type - overloaded functions
/// [remove_reference](https://en.cppreference.com/w/cpp/types/remove_reference)
char func_type(const int& x)
{
assert(is_const::type>::value);
assert(is_lvalue_reference::value);
return 'C';
}
char func_type(int& x)
{
assert(is_lvalue_reference::value);
return 'L';
}
char func_type(int&& x)
{
assert(is_rvalue_reference::value);
return 'R';
}
/// [Forwarding reference](https://en.cppreference.com/w/cpp/language/reference#Forwarding_references)
template
char func_type_template(T&& x) // x is a forwarding reference
{
// x is not R-value here
assert(func_type(x) != 'R');
// x can be forwarded as R or L value
// https://en.cppreference.com/w/cpp/utility/forward
return func_type(forward(x)); // like func_type((T)(x));
}
/**
[References](https://en.wikipedia.org/wiki/Reference_(C++))
[is_reference](https://en.cppreference.com/w/cpp/types/is_reference),
[ref](https://en.cppreference.com/w/cpp/utility/functional/ref),
[reference_wrapper](https://en.cppreference.com/w/cpp/utility/functional/reference_wrapper)
*/
void references_11()
{
// https://en.cppreference.com/w/cpp/language/reference
assert(is_reference::value);
// L-value:
assert(is_lvalue_reference::value);
// R-value
assert(is_rvalue_reference::value);
const int c = 1;
int i = 2;
assert(func_type(3) == 'R');
assert(func_type(c) == 'C');
assert(func_type(move(i)) == 'R');
assert(func_type_template(c) == 'C');
assert(func_type_template(i) == 'L');
assert(func_type_template(3) == 'R');
reference_wrapper rw = i;
rw.get() = 3;
assert(i == 3);
auto cr = cref(i);
assert(cr == 3);
}
/**
[direct_initialization](https://en.cppreference.com/w/cpp/language/direct_initialization)
[zero_initialization](https://en.cppreference.com/w/cpp/language/zero_initialization)
[list_initialization](https://en.cppreference.com/w/cpp/language/list_initialization)
[initializer_list](https://en.cppreference.com/w/cpp/utility/initializer_list)
[Member_initialization](https://en.cppreference.com/w/cpp/language/data_members#Member_initialization)
[aggregate_initialization](https://en.cppreference.com/w/cpp/language/aggregate_initialization)
[reference_initialization](https://en.cppreference.com/w/cpp/language/reference_initialization)
*/
void init_11()
{
struct C {
int a, b, c;
};
auto o2 = C { 1, 2, 3 };
C o3 { 1, 2, 3 };
(void)o3;
auto uses_il = [](initializer_list il) {
assert(*il.begin() == 3);
assert(il.size() == 4);
};
uses_il({ 3, 2, 1, 0 });
auto z1 = C();
C z2 = {};
auto z3 = C {};
assert(!z1.a);
assert(!z2.a);
assert(!z3.a);
array a { 1, 2 };
}
/**
Trailing return type
https://en.cppreference.com/w/cpp/language/function
https://www.ibm.com/support/knowledgecenter/en/ssw_ibm_i_73/rzarg/trailing_return.htm
*/
/// https://en.cppreference.com/w/cpp/language/auto
auto auto_int = 1;
// int before(int a) { return a; }
auto trailing_return_type(int a) -> int
{
return a;
}
/// [copy_elision](https://en.cppreference.com/w/cpp/language/copy_elision)
void copy_elision_demo()
{
struct Obj2 {
Obj2* orig = this;
int ballast[4];
};
auto&& o2 = []() { return Obj2(); }();
assert(&o2 == o2.orig);
}
void func_11()
{
class functor {
int y = 1;
public:
int operator()(int a) const
{
return a + y;
}
};
functor ft;
assert(ft(1) == 2);
// https://en.cppreference.com/w/cpp/utility/functional/function
function ft2 = ft;
assert(ft(2) == 3);
return;
// https://en.cppreference.com/w/cpp/utility/functional/bind
auto binded = bind(ft2, 3);
assert(binded() == 5);
copy_elision_demo();
}
static_assert(__cpp_constexpr, "");
/// https://en.cppreference.com/w/cpp/language/constexpr
constexpr int constexpr_factorial(int n)
{
return n <= 1 ? 1 : (n * constexpr_factorial(n - 1));
}
/// https://en.cppreference.com/w/cpp/language/parameter_pack
template
T constexpr adder(T v)
{
return v;
}
template
T constexpr adder(T first, Args... args)
{
return first + adder(args...);
}
static_assert(adder(1, 2, 3) == 6, "");
static_assert(adder(1, 2, 3) == 6, "");
struct Base11 {
virtual void method1();
virtual void method2();
};
struct Derived11 : Base11 {
void method1() override; ///< [override](https://en.cppreference.com/w/cpp/language/override)
void method2() final; ///< [final](https://en.cppreference.com/w/cpp/language/final)
};
void language_11()
{
types_11();
references_11();
init_11();
auto r = trailing_return_type(1);
(void) r;
dynamic_memory_11();
func_11();
}
/// @} lang11
/**
@defgroup lambda11 Lambda
https://en.cppreference.com/w/cpp/language/lambda
https://www.geeksforgeeks.org/lambda-expression-in-c/
@{
*/
static void lambda_basics(void)
{
auto annotated_named_lambda_expression = // optional name
[] // capture clause
() // optional list of arguments
{}; // body
// Primitive named lambdas are just like closure functions:
// https://en.wikipedia.org/wiki/Closure_(computer_programming)
// declaration like a function:
// void closure() { };
auto closure = [] {};
closure();
// with arguments
auto pass = [](int a) { return a; };
assert(pass(5) == 5);
// lambda captures external value
int c = 1;
auto get_i = [=]() { return c; };
assert(get_i() == 1);
// lambda captures external variable by reference
// with omitted arguments and return type
auto inc_get = [&] { return ++c; };
assert(inc_get() == 2);
assert(inc_get() == 3);
// annotated expanded empty inline lambda call:
[] // capture
() // optional list of arguments
-> void // optional return value
{} // body
(); // call with arguments
// annotated expanded sample inline lambda call:
c = // result
[c] // capture
(int a) // an argument
-> int // return value
{ return c + a; } // body
(1); // call with argument
assert(c == 4);
// inline lambda which is called in place
// https://en.wikipedia.org/wiki/Anonymous_function
// assert((1 + 1) == 2);
assert([](int a) { return a + 1; }(1) == 2);
// Actually calling lambda inline is useless
// and is provided only for demonstration.
}
/// @cond
static int glob;
/// @endcond
static void lambda_capture(void)
{
// read only
int i = 2;
assert([=] { return i; }() == 2);
// read and write access
[&](int a) { i = a; }(3);
assert(i == 3);
// explicit r/o and r/w
int j;
[i, &j]() { j = i; }();
assert(j == i);
// r/o by default
i++;
[=, &j]() { j = i; }();
assert(j == i);
// r/w by default
i++;
[&, i]() { j = i; }();
assert(j == i);
// can access globals anyway
auto inc_global = []() { return ++glob; };
assert(inc_global() == 1);
assert(inc_global() == 2);
}
/// [utility](https://en.cppreference.com/w/cpp/utility)
void utils_11()
{
pair bounds = minmax({3, 2, 1});
assert(bounds.first == 1);
assert(bounds.second == 3);
int min, max;
tie(min, max) = bounds;
assert(min == 1);
int n = 1;
auto t = make_tuple(0, "one", 3.14, ref(n), n);
n = 2;
//cerr << func_type(get<2>(t)) << '\n';
assert(is_arithmetic::value);
//assert(is_arithmetic(t))>::value);
assert(get<3>(t) == 2);
assert(get<4>(t) == 1);
}
/// [container](https://en.cppreference.com/w/cpp/container)
template
void test_list_container(L& l)
{
l.push_front(0);
assert(l.front() == 0);
l.emplace_front(1);
assert(l.front() == 1);
l.pop_front();
L l2;
swap(l, l2);
l.swap(l2);
}
void container_11()
{
// [list_initialization](https://en.cppreference.com/w/cpp/language/list_initialization)
vector v = { 1, 2, 3 };
assert(v.data()[2] == 3);
v.shrink_to_fit();
v.emplace(v.cbegin(), 0);
assert(v.front() == 0);
v.emplace_back(4);
assert(v.back() == 4);
array a1, a2;
swap(a1, a2);
/// [forward_list](https://en.cppreference.com/w/cpp/container/forward_list)
forward_list fl;
test_list_container(fl);
fl.insert_after(fl.cbegin(), 3);
assert(*(next(fl.begin())) == 3);
fl.erase_after(fl.cbefore_begin()); // like fl.pop_front();
assert(fl.front() == 3);
fl.pop_front();
list l;
test_list_container(l);
l.emplace_back(0);
l.emplace(l.begin(), 2);
assert(l.front() == 2);
l.sort();
deque d;
test_list_container(d);
d.emplace_back(0);
stack s, s2;
s.emplace(1);
s.swap(s2);
}
/// [algorithm](https://en.cppreference.com/w/cpp/algorithm)
void algo_11()
{
vector v = { 1, 2, 3 };
assert(find(begin(v), end(v), 0) == end(v));
assert(find(begin(v), end(v), 1) != end(v));
// https://en.cppreference.com/w/cpp/container/vector/erase
// https://en.cppreference.com/w/cpp/algorithm/remove
v.erase(remove_if(v.begin(), v.end(), [](unsigned char x) { return x == 2; }), v.end());
assert(v.size() == 2);
vector r(v.size());
reverse_copy(begin(v), end(v), r.begin());
assert(r[0] > r[1]);
// https://en.cppreference.com/w/cpp/string/basic_string/erase
string s = "1 2 3";
s.erase(remove_if(s.begin(), s.end(), [](unsigned char x) { return isspace(x); }), s.end());
assert(s == "123");
}
/// Compare with @ref sort_03
struct comp {
template
bool operator()(const T& l, const T& r) const
{
return l.second < r.second;
}
};
void sort_11()
{
/// [array](https://en.cppreference.com/w/cpp/container/array)
array s { 5, 7, 4, 2, 8, 6, 1, 9, 0, 3 };
sort(s.begin(), s.end(),
// sort using a lambda expression
[](int a, int b) { return a > b; });
// https://stackoverflow.com/questions/18045208/override-mapcompare-with-lambda-function-directly
auto reverse = map> {
[](const string& a, const string& b) { return a > b; }
}
= {
{ "a", 2 },
{ "b", 1 },
{ "c", 0 },
};
assert(reverse.begin()->first == "c");
assert(reverse.begin()->second == 0);
// https://www.techiedelight.com/sort-map-values-cpp/
typedef pair pair;
vector vec = {
{ "a", 2 },
{ "b", 1 },
{ "c", 0 },
};
sort(vec.begin(), vec.end(),
[](const pair& l, const pair& r) { return l.second < r.second; });
assert(vec.begin()->first == "c");
set<:pair int>, comp> t = {
{ "a", 2 },
{ "b", 1 },
{ "c", 0 },
};
assert(t.begin()->first == "c");
}
/// @}
/**
@defgroup lambda11_complex More complex Lambdas
@{
*/
/// @cond
/// [function](https://en.cppreference.com/w/cpp/utility/functional/function)
// int use_lambda(int a; int (func*)(int))
static int use_lambda(int a, function f)
{
// lambda argument is like pointer to functions
return f(a);
}
static function g_f;
static void set_lambda(function&& f)
{
g_f = f;
}
static int call_lambda(int a)
{
return g_f(a);
}
/// @endcond
static void lambda_complex(void)
{
auto increment = [](int a) -> int { return a + 1; };
assert(increment(5) == 6);
// named lambda as argument
assert(use_lambda(2, increment) == 3);
set_lambda(increment);
assert(call_lambda(3) == 4);
// inline lambda as argument
assert(use_lambda(1, [](int a) { return a + 1; }) == 2);
int x = 0;
[x]() mutable { assert(++x); }();
assert(x == 0);
}
/// @} lambda11_complex
/**
@defgroup threads11 Threads
[threads](https://en.cppreference.com/w/cpp/thread)
@{
*/
/// @cond
// just function with delay for demonstration
int lento(int a = 0)
{
this_thread::yield();
this_thread::sleep_for(chrono::milliseconds(50));
return a;
}
/// @endcond
/**
[condition_variable](https://en.cppreference.com/w/cpp/thread/condition_variable)
[notify_one](https://en.cppreference.com/w/cpp/thread/condition_variable/notify_one)
*/
void condition_variable_11()
{
mutex m;
int stage = 0;
condition_variable cv;
thread th(
[&m, &stage, &cv] {
unique_lock lk(m);
cv.wait(lk, [&stage] { return stage == 1; });
stage = 2;
lk.unlock();
cv.notify_one();
});
// locking block
{
unique_lock lk(m);
// https://en.cppreference.com/w/cpp/thread/condition_variable/wait_for
assert(cv.wait_for(lk, chrono::milliseconds(0)) == cv_status::timeout);
assert(!cv.wait_for(lk, chrono::milliseconds(0),[]{return false;}));
}
{
unique_lock lk(m);
stage = 1;
}
cv.notify_one();
unique_lock lk(m);
cv.wait(lk, [&stage] { return stage == 2; });
th.join();
}
void threads_11()
{
this_thread::yield();
assert(hash<:id>()(this_thread::get_id()));
this_thread::sleep_for(chrono::nanoseconds(1));
promise p;
future f = p.get_future();
int v = 0;
thread t([&p, &v] {
lento();
p.set_value(2);
v = 3;
});
assert(v == 0);
assert(f.get() == 2);
lento();
assert(v == 3);
thread t2;
t2.swap(t);
assert(!t.joinable());
assert(t2.joinable());
t2.join();
try {
t2.join();
t2.detach();
} catch (const system_error& e) {
assert(e.code().value() == 22);
}
assert(!t2.joinable());
// detach demo
{
thread t3([&p, &v] {
v = 4;
});
t3.detach();
std::thread { []() { assert(1); } }.detach();
}
lento();
assert(v == 4);
condition_variable_11();
}
void mutex_11()
{
int unguarded = 0, guarded = 0;
mutex m;
thread t1([&unguarded, &guarded, &m] {
unguarded = lento(unguarded) + 1;
lock_guard guard(m);
guarded = lento(guarded) + 1;
});
thread t2([&unguarded, &guarded, &m] {
unguarded = lento(unguarded) + 1;
lock_guard guard(m);
guarded = lento(guarded) + 1;
});
assert(unguarded == 0);
assert(guarded == 0);
t1.join();
t2.join();
assert(unguarded == 1);
assert(guarded == 2);
}
/// @} threads11
/**
@{
TODO:
function get_a = a;
https://en.cppreference.com/w/cpp/language/attributes
https://en.cppreference.com/w/cpp/language/string_literal
https://en.cppreference.com/w/cpp/language/character_literal
https://en.cppreference.com/w/cpp/language/user_literal
https://en.cppreference.com/w/cpp/language/initializer_list
https://en.cppreference.com/w/cpp/utility/declval
https://en.cppreference.com/w/cpp/language/range-for
https://en.cppreference.com/w/cpp/types/is_move_constructible
https://en.cppreference.com/w/cpp/types/is_constructible
@}
*/
void sig(int)
{
abort();
}
int main(void)
{
signal(SIGALRM, sig);
alarm(1);
language_11();
lambda_basics();
lambda_capture();
lambda_complex();
utils_11();
container_11();
algo_11();
sort_11();
static_assert(constexpr_factorial(4), "");
threads_11();
mutex_11();
return 0;
}
/// @}