mirror of
https://github.com/cirosantilli/linux-kernel-module-cheat.git
synced 2026-01-23 02:05:57 +01:00
cpp: initializer list constructor
This commit is contained in:
105
userland/cpp/initializer_list_constructor.cpp
Normal file
105
userland/cpp/initializer_list_constructor.cpp
Normal 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
|
||||||
|
}
|
||||||
@@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user