learn more c++, it never ends

This commit is contained in:
Ciro Santilli 六四事件 法轮功
2020-03-19 00:00:00 +00:00
parent 082166a360
commit d09a0d97b8
6 changed files with 277 additions and 29 deletions

View File

@@ -0,0 +1,22 @@
// https://cirosantilli.com/linux-kernel-module-cheat#cpp
constexpr int f() {
int i = 0;
while (1)
i += 1;
return i;
}
constexpr int g() {
return g();
}
int main() {
#if 0
// GCC 9.2.1. error: constexpr loop iteration count exceeds limit of 262144 (use -fconstexpr-loop-limit= to increase the limit)
static_assert(f() == 0);
// GCC 9.2.1. error: constexpr evaluation depth exceeds maximum of 512 (use -fconstexpr-depth= to increase the maximum)
static_assert(g() == 0);
#endif
}

View File

@@ -1,23 +1,30 @@
// https://cirosantilli.com/linux-kernel-module-cheat#cpp
#if __cplusplus >= 201703L
#include <cassert>
#include <type_traits>
template <class T>
template<typename T>
struct MyClass {
int myFunc() {
if constexpr(std::is_integral<T>())
return 1;
else
return 2;
MyClass() : myVar{0} {}
void modifyIfNotConst() {
if constexpr(!isconst) {
myVar = 1;
}
}
T myVar;
static constexpr bool isconst = std::is_const<T>::value;
};
#endif
int main() {
#if __cplusplus >= 201703L
assert(MyClass<int>().myFunc() == 1);
assert(MyClass<float>().myFunc() == 2);
MyClass<double> x;
MyClass<const double> y;
x.modifyIfNotConst();
y.modifyIfNotConst();
assert(x.myVar == 1);
assert(y.myVar == 0);
#endif
}

View File

@@ -0,0 +1,199 @@
// https://cirosantilli.com/linux-kernel-module-cheat#cpp-initialization-types
#include <cassert>
#include <type_traits>
// zero-initialization because has static storage
// just like a static "local" function variable.
int global;
int main() {
// First let's list how different initializations are done explicitly in the code.
{
struct C {
int i;
constexpr C() : i(0) {}
constexpr C(int i) : i(i) {}
};
// Default-initialization.
{
C i;
C *j = new C;
}
// Value initialization.
{
C i{};
C j = C();
C k = C{};
C *l = new C();
C *m = new C{};
}
// Direct initialization.
{
C i(1);
C j{1};
C *k = new C(1);
}
// Zero initialization
{
static C i;
}
// Most vexing parse, function declaration!
{
C myfunc();
}
// The syntax goes for primitive types. These serve as the basis
// for the recursive definition..
{
// Default.
int i;
// Following the cases at:
// https://en.cppreference.com/w/cpp/language/default_initialization
// i is POD and is not an array: therefore nothing is done.
//assert(i == ?);
// Value.
constexpr int j{};
// Following the cases at:
// https://en.cppreference.com/w/cpp/language/value_initialization
// j is not a class type, and is not an array type. Therefore it is zero initialized.
static_assert(j == 0);
// Direct.
constexpr int k{1};
// Following the cases at:
// https://en.cppreference.com/w/cpp/language/direct_initialization
// is not array, not class, not "if T is a non-class type but the source type is a
// class type" whatever that means, and not bool, therefore standard conversion is used
// and the value is set.
static_assert(k == 1);
}
}
// Now, let's see which implicit initializations are done for each case recursively.
{
{
struct C { int i; };
static_assert(std::is_default_constructible<C>());
static_assert(std::is_aggregate<C>());
// Default
C a;
// Following the cases at:
// https://en.cppreference.com/w/cpp/language/default_initialization
// - non-POD? no
// - array? no
// - then: nothing is done.
//assert(i == ?);
// Value
constexpr C b{};
// Following the cases at:
// https://en.cppreference.com/w/cpp/language/value_initialization
// - class type with no default constructor? no
// - default constructor that is neither user-provided nor deleted: yes
// - zero initialize
// - has a non-trivial default constructor
// - no
assert(b.i == 0);
// Aggregate
constexpr C c{5};
static_assert(c.i == 5);
// Zero
static C d;
assert(d.i == 0);
}
{
struct C {
int i;
constexpr C() : i(3) {};
constexpr C(int i) : i(i) {};
};
static_assert(!std::is_pod<C>());
// Default
constexpr C a;
// Following the cases at:
// https://en.cppreference.com/w/cpp/language/default_initialization
// - non-POD? yes. Therefore: call C(). which initializes i.
static_assert(a.i == 3);
// Value
constexpr C b{};
// Following the cases at:
// https://en.cppreference.com/w/cpp/language/value_initialization
// - class type with no default constructor? no
// - user-provided default constructor? yes. Therefore, default initialize the object.
// So we fall on the above case, and the variable does get set.
static_assert(b.i == 3);
// Direct
constexpr C c{5};
// Following the cases at:
// https://en.cppreference.com/w/cpp/language/_initialization
// - array type? no
// - class type? yes. Call constructor.
static_assert(c.i == 5);
}
{
struct C {
int i;
constexpr C(int i) : i(i) {};
};
static_assert(!std::is_pod<C>());
static_assert(!std::is_default_constructible<C>());
#if 0
// Cannot be default initialized if not default constructible.
// error: no matching function
constexpr C a;
#endif
#if 0
// Cannot be value initialized if not default constructible.
// error: no matching function
C b{};
#endif
// Direct initialize
constexpr C c{5};
static_assert(!std::is_pod<C>());
// - class type with no default constructor? yes
}
//struct A { T t; A() : t() {} };
//A a; // t is value-initialized
//A a{}; // t is value-initialized
//struct A { T t; A() : t{} {} };
//A a; // t is TODO
//A a{}; //
//struct A { T t; A() {} };
//A a; // t is TODO
//A a{}; // t is TODO
//struct A { T t; A() = default };
//A d; // t is TOAO
//A d{}; // t is TOAO
//struct A { T t; A() = deleted };
//A e; // t is TODO
//A e{}; // t is TODO
//struct A { T t; A(T t) {} };
//A f; // t is TODO
//A f{}; // t is TODO
}
}

View File

@@ -1,20 +1,18 @@
// https://cirosantilli.com/linux-kernel-module-cheat#cpp
#include <cassert>
int main() {
struct D {
int i;
D() {}
D(int i) : i(i) {}
constexpr D() : i(0) {}
constexpr D(int i) : i(i) {}
};
struct C {
int i;
C() : i(1) {}
C(int i) : i(i) {}
C(const D& d) : i(d.i) {}
constexpr C() : i(1) {}
constexpr C(int i) : i(i) {}
constexpr C(const D& d) : i(d.i) {}
};
// Declares *FUNCTION* called `c` that returns `C` inside function main.
@@ -25,7 +23,7 @@ int main() {
// Therefore there would be not way for C++ to distinguish between the two,
// and still be backwards compatible with C.
{
C c();
constexpr C c();
#if 0
// ERROR: function definition is not possible inside another function.
@@ -37,24 +35,24 @@ int main() {
// If you want to call a default constructor, use:
{
C c;
assert(c.i == 1);
constexpr C c;
static_assert(c.i == 1);
}
// For non-default constructors, literal arguments disambiguate
// things as this syntax could not possibly be a function declaration.
{
C c(2);
assert(c.i == 2);
constexpr C c(2);
static_assert(c.i == 2);
}
// But sometimes even arguments are not enough: here D()
// is interpreted as "a function of type `D f()`"
{
C c(D(2));
constexpr C c(D());
#if 0
// error: request for member i in c, which is of non-class type main()::C(main()::D (*)())
assert(c.i == 2);
static_assert(c.i == 0);
#endif
}
@@ -63,22 +61,22 @@ int main() {
{
// Extra parenthesis.
{
C c((D(2)));
assert(c.i == 2);
constexpr C c((D(2)));
static_assert(c.i == 2);
}
// Initialize through assignment. TODO likely guaranteed to be cost-free,
// but confirm.
{
C c = C((D(2)));
assert(c.i == 2);
constexpr C c = C((D(2)));
static_assert(c.i == 2);
}
// Initializer list. Only works if there is no initializer_list constructor.
// Only works in general if c does not have an ambiguous initializer_list constructor though.
{
C c{D(2)};
assert(c.i == 2);
constexpr C c{D(2)};
static_assert(c.i == 2);
}
}
}