cpp: initializer list constructor

This commit is contained in:
Ciro Santilli 六四事件 法轮功
2020-02-28 00:00:01 +00:00
parent 78ce2dabe1
commit 44ac89eb72
2 changed files with 139 additions and 7 deletions

View File

@@ -0,0 +1,105 @@
// https://cirosantilli.com/linux-kernel-module-cheat#cpp
//
// # Brace enclosed initializer list
//
// # List initialization
//
// # Initializer list constructor
//
// Applications:
//
// - you don't know beforehand how many arguments a constructor should receive
//
// For example, the stdlib std::vector class gets an initializer list constructor on C++11,
// which allows one to initialize it to any constant.
//
// TODO could this not be achieved via cstdarg?
#include <cassert>
#include <initializer_list>
#include <vector>
int main() {
#if __cplusplus >= 201103L
// STL std::vector usage example
{
std::vector<int> v{0, 1};
// SAME.
//std::vector<int> v = std::vector<int>({0, 1});
assert(v[0] == 0);
assert(v[1] == 1);
assert(v == std::vector<int>({0, 1}));
assert((v == std::vector<int>{0, 1}));
// Assignment also works via implicit conversion.
v = {1, 0};
assert((v == std::vector<int>{1, 0}));
// ERROR: TODO why no implicit conversion is made?
//assert((v == {0, 1}));
}
// How to implement one yourself.
{
struct InitializerListCtor {
std::vector<int> v;
InitializerListCtor(int i, int j) {
v.push_back(i);
v.push_back(j + 1);
}
InitializerListCtor(std::initializer_list<int> list) {
for (auto& i : list)
v.push_back(i);
}
InitializerListCtor(int before, std::initializer_list<int> list, int after) {
v.push_back(before + 1);
for (auto& i : list)
v.push_back(i);
v.push_back(after - 1);
}
};
// Initializer list constructor is called, not the (int,int) one.
{
InitializerListCtor o{0, 1};
assert((o.v == std::vector<int>{0, 1}));
}
// 3 param constructor is called
{
InitializerListCtor o(0, {0, 0,}, 0);
assert((o.v == std::vector<int>{1, 0, 0, -1}));
}
}
// # auto and initializer lists
//
// auto rule: brace initializer can be bound to auto
//
// http://en.cppreference.com/w/cpp/utility/initializer_list
//
{
{
// TODO GCC 5.1 does not allow this, which conflicts with
// http://en.cppreference.com/w/cpp/utility/initializer_list
// Who is right?
// auto InitializerListCtor{0, 1, 2};
// SAME:
//initializer_list<int> l{0, 1, 2};
//assert(l.size() == 3);
//assert(*l.begin() == 0);
}
// The rule for auto makes this ranged for work.
// TODO why here? I see an `int`, not an `auto`
int i = 0;
for (auto x : {0, 1, 2}) {
assert(x == i);
i++;
}
}
#endif
}

View File

@@ -1,17 +1,20 @@
// https://cirosantilli.com/linux-kernel-module-cheat#cpp // https://cirosantilli.com/linux-kernel-module-cheat#cpp
#include "common.hpp" #include <cassert>
int main() { int main() {
struct D {
int i;
D() {}
D(int i) : i(i) {}
};
struct C { struct C {
int i; int i;
C() : i(1) {} C() : i(1) {}
C(int i) : i(i) {} C(int i) : i(i) {}
}; C(const D& d) : i(d.i) {}
struct D {
D() {}
}; };
// Declares *FUNCTION* called `c` that returns `C` inside function main. // Declares *FUNCTION* called `c` that returns `C` inside function main.
@@ -46,12 +49,36 @@ int main() {
} }
// But sometimes even arguments are not enough: here D() // But sometimes even arguments are not enough: here D()
// could matn that the declared `c` // is interpreted as "a function of type `D f()`"
{ {
C c(D()); C c(D(2));
#if 0 #if 0
// error: request for member i in c, which is of non-class type main()::C(main()::D (*)()) // error: request for member i in c, which is of non-class type main()::C(main()::D (*)())
assert(c.i == 2); assert(c.i == 2);
#endif #endif
} }
// Solving the most vexing parse.
// https://stackoverflow.com/questions/13249694/avoid-the-most-vexing-parse
{
// Extra parenthesis.
{
C c((D(2)));
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);
}
// 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);
}
}
} }