Primary categories
Every expression has a primary value category associated with it
- prvalue: pure rvalue
- xvalue: eXpiring value
- lvalue: glvalue that is not an xvalue
https://github.com/yuchdev/CppBooks
According to chatgpt:
new / delete →
std::unique_ptrmalloc() / free() → RAII wrapperslock() / unlock() →
lock_guardopen() / close() → file wrapper
classesauto variablesauto remains only as a storage class
specifier.Links:
noexcepttrue if if an expression is declared
to not throw any exceptions.'
void no_throw() noexcept;noexcept my-expr ???Both of these are effectively the same:
void g() noexcept(false);
void g();mutableFormat:
[capture](parameters) specifiers -> return_type {
// function body
};
Examples:
auto f = [] {};
auto hello = [] { std::cout << "Hello\n"; };
voidauto add = [](int a, int b) { return a + b; };
intauto divide = [](int a, int b) -> double { return static_cast<double>(a) / b;} ;
[=]: capture everything (by value)[*]: capture everything (by reference)[=, &x]: capture all by value, x by
reference[&, x]: capture everything by reference,
x by valuestatic_casthttps://en.cppreference.com/cpp/language/value_category
Every expression has a primary value category associated with it
An example from the internet. This is supposed to take a day to compile on a dual-core processor with 1GB RAM: https://cpptruths.blogspot.com/2005/11/c-templates-are-turing-complete.html
template<int Depth, int A, typename B>
struct K17 {
static const int x =
K17 <Depth+1, 0, K17<Depth,A,B> >::x
+ K17 <Depth+1, 1, K17<Depth,A,B> >::x
+ K17 <Depth+1, 2, K17<Depth,A,B> >::x
+ K17 <Depth+1, 3, K17<Depth,A,B> >::x
+ K17 <Depth+1, 4, K17<Depth,A,B> >::x;
};
template <int A, typename B>
struct K17 <16,A,B> {
static const int x = 1;
};
static const int z = K17 <0,0,int>::x;
int main(void) { }See:
(Thanks to Kevin for introducing me to this.)
The example program which drew lot of attention to TMP in C++: http://www.erwin-unruh.de/primorig.html
The original version is no longer valid CPP, but a version here works.
#ifndef LAST
#define LAST 18
#endif
enum {
IS_PRIME,
NO_PRIME,
CONTINUE
};
template <int candidate, int testValue>
struct Eval {
enum {
mode =
testValue * testValue > candidate ? IS_PRIME :
candidate % testValue == 0 ? NO_PRIME :
CONTINUE
};
};
template <int candidate, int prime, int mode >
struct sieve {
enum {
next = prime + 1,
isPrime = sieve<candidate, next,
Eval<candidate, next>::mode>::isPrime
};
};
template <int candidate, int prime>
struct sieve<candidate, prime, IS_PRIME> {
enum { isPrime = IS_PRIME };
};
template <int candidate, int prime>
struct sieve<candidate, prime, NO_PRIME > {
enum { isPrime = NO_PRIME };
};
template <int prime>
struct test {
enum {isPrime = sieve<prime, 2, Eval<prime, 2>::mode>::isPrime };
};
template <int prime, int isPrime>
struct show {
static void f() {
show<prime - 1, test<prime - 1>::isPrime >::f();
}
};
template <int prime>
struct show<prime, IS_PRIME> {
static int *f() {
show<prime - 1, test<prime - 1>::isPrime >::f();
int x;
return &x;
}
};
template <>
struct show<1, IS_PRIME> {
static void f() {}
};
template <int prime>
void primes() {
show<prime, test<prime>::isPrime>::f();
}
int main() {
// 'instantiation' messages because of the suggested grep command
static_assert(LAST >= 2,
"instantiation of LAST must be >= 2");
primes<LAST>();
static_assert(0,
"instantiation of compilation terminated");
}Run with:
$ g++ input.cpp -DLAST=30 2>&1 | grep 'instantiation of'
input.cpp: In instantiation of ‘static int* show<prime, 0>::f() [with int prime = 29]’:
input.cpp: In instantiation of ‘static int* show<prime, 0>::f() [with int prime = 23]’:
input.cpp: In instantiation of ‘static int* show<prime, 0>::f() [with int prime = 19]’:
input.cpp: In instantiation of ‘static int* show<prime, 0>::f() [with int prime = 17]’:
input.cpp: In instantiation of ‘static int* show<prime, 0>::f() [with int prime = 13]’:
input.cpp: In instantiation of ‘static int* show<prime, 0>::f() [with int prime = 11]’:
input.cpp: In instantiation of ‘static int* show<prime, 0>::f() [with int prime = 7]’:
input.cpp: In instantiation of ‘static int* show<prime, 0>::f() [with int prime = 5]’:
input.cpp: In instantiation of ‘static int* show<prime, 0>::f() [with int prime = 3]’:
input.cpp: In instantiation of ‘static int* show<prime, 0>::f() [with int prime = 2]’:
Allows the constitutent values of a compound type to be assigned to variables.
See:
void foo(int, double)
{
// The int and double cannot be used in body
// since they are unnamed.
}Another example from Boost: https://www.boost.org/doc/libs/latest/doc/html/proto/users_guide.html#boost_proto.users_guide.getting_started.hello_calculator.constructing_expression_trees
template<int I>
double operator()(proto::tag::terminal, placeholder<I>) const
{
return this->args[I];
} & or && qualifies whether this
must refer to an lvalue or rvalue.
&: lvalue&&: rvalue// Only lvalues can call
#include<iostream>
class Foo {
public:
void hello() & {
std::cout << "lvalue\n";
}
};
int main() {
// Works fine.
Foo obj;
obj.hello();
// Error because of the '&' in function delcaration
Foo{}.hello();
}Another one:
// Only rvalues (temporary values) can call
#include<iostream>
class Bar {
public:
void hello() && {
std::cout << "rvalue\n";
}
};
int main() {
// Error because of the '&&' in function delcaration
Bar obj;
obj.hello();
// Works fine.
Bar{}.hello();
}With both versions via function overloading:
#include<iostream>
class Foo {
public:
void hello() & {
std::cout << "lvalue\n";
}
void hello() && {
std::cout << "rvalue\n";
}
};
int main() {
Foo obj;
obj.hello();
Foo{}.hello();
}Constructor that makes the object as a copy of a pre-existing object
If not explicitly defined, compiler tries to generate one, by copying attributes.
Different from copy assignment
Copy constructor can be disabled by deleting it.
struct Lock {
Lock(const Lock&) = delete;
};operator()#include<iostream>
struct Twice {
int operator()(int a) {
return 2*a;
}
};
int main() {
Twice obj;
std::cout<< obj(5) <<std::endl; /* 10 */
}regex (C++11)Available as a standard library since C++11.
Type of regexes: std::regex
Find match in string for a regex:
std::regex_search(str, rgx)
vectorvector<T> is
0#include<iostream>
#include<vector>
int main() {
std::vector<int> v1 = {1, 2, 3};
std::cout << v1[0] << std::endl; // 1
std::vector<int> v2(3);
std::cout << v2[0] << std::endl; // 0
std::vector<bool> v3(3);
std::cout << v3[0] << std::endl; // 0
}tuplehttps://en.cppreference.com/w/cpp/utility/tuple
An example adapted from cppreference:
#include<iostream>
#include<tuple>
int main() {
std::tuple<int, char, std::string> ics;
ics = {5, 'a', "hello"};
std::cout << "ics[0]: " << std::get<0>(ics) << std::endl;
std::cout << "ics[1]: " << std::get<1>(ics) << std::endl;
std::cout << "ics[2]: " << std::get<2>(ics) << std::endl;
// Getting values in a tuple to vars.
// Types auto-inferred due to the 'auto' use.
// The is a C++17 feature named 'structured binding'.
// GCC (>=7 only) needs -std=c++17
auto [ival, cval, sval] = ics;
std::cout << std::endl;
std::cout << "ival: " << ival << std::endl;
std::cout << "cval: " << cval << std::endl;
std::cout << "sval: " << sval << std::endl;
// Could also be done with std::tie for tuple, but is more verbose.
int ival2;
char cval2;
std::string sval2;
std::tie(ival2, cval2, sval2) = ics;
std::cout << std::endl;
std::cout << "ival2: " << ival2 << std::endl;
std::cout << "cval2: " << cval2 << std::endl;
std::cout << "sval2: " << sval2 << std::endl;
}
/*
ics[0]: 5
ics[1]: a
ics[2]: hello
ival: 5
cval: a
sval: hello
ival2: 5
cval2: a
sval2: hello
*/Similar:
type_traitshttps://en.cppreference.com/cpp/header/type_traits
Ask questions about type of values at compile time. Useful for TMP.
is_copy_constructible_v: check if copy constructor can
be used on a type
static_assert(std::is_copy_constructible_v<T>, "Needs copying");is_trivially_copy_constructible_v:is_nothrow_copy_constructible_v:See:
__FUNCTION__ (non-standard): macro giving name of
current function in gccvoid': I guess use of either
const or volatile qualifier ??https://en.cppreference.com/cpp/memory#Smart_pointers
deleteSee:
unique_ptrhttps://en.cppreference.com/cpp/memory/unique_ptr
Note: auto_ptr is apparently something old which should
no longer be used.
shared_ptrweak_ptrSingle object
Array of objects:
Can be made with using
using IntRef = int&;& and *This is the style followed by gcc.
& and * written 'as part of' type–
int* a, b;means only a is a pointer, b is
just an ~int. This is why some people prefer to write
int *a, b;Instead, we can restrict number of variables per declaration to one:
int *a;
int b;clang-format --style=Google
clang-format --style=LLVM
Config:
IndentWidth: 4
UseTab: Never
Make a fresh user-level config with:
clang-format -style=Google -dump-config > ~/.clang-format
constexpr