Example Code: Modern C++#
Manipulate data using a raw pointer (
01_copy.cpp
).#1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 | #include <iostream>
#include <cstdlib>
#include <algorithm>
#include <memory>
class IsCopied
{
public:
static IsCopied & instance()
{
// This is a singleton.
static IsCopied inst;
return inst;
}
IsCopied & on() { m_status = true; return *this; }
operator bool() const { return m_status; }
~IsCopied() = default;
private:
IsCopied() : m_status(false) {}
IsCopied(IsCopied const & ) = delete;
IsCopied(IsCopied &&) = delete;
IsCopied & operator=(IsCopied const & ) = delete;
IsCopied & operator=(IsCopied &&) = delete;
bool m_status;
}; /* end class IsCopied */
class Data
{
public:
constexpr const static size_t NELEM = 1024*8;
Data()
{
std::cout << "Data constructed @" << this << std::endl;
}
Data(Data const & other)
{
copy_from(other);
std::cout << "Data copied to @" << this << " from @" << &other << std::endl;
}
Data & operator=(Data const & other)
{
copy_from(other);
std::cout << "Data copy assigned to @" << this << " from @" << &other << std::endl;
return *this;
}
~Data()
{
std::cout << "Data destructed @" << this << std::endl;
}
size_t size() const { return NELEM; }
int operator[](size_t it) const { return m_buffer[it]; }
int & operator[](size_t it) { return m_buffer[it]; }
bool is_manipulated() const
{
for (size_t it=0; it < size(); ++it)
{
if ((*this)[it] != it) { return false; }
}
return true;
}
private:
void copy_from(Data const & other)
{
for (size_t it=0; it < NELEM; ++it)
{
m_buffer[it] = other.m_buffer[it];
}
// Mark copied.
IsCopied::instance().on();
}
// A lot of data that we don't want to reconstruct.
int m_buffer[NELEM];
}; /* end class Data */
void manipulate_with_reference(Data & data, int value)
{
std::cout << "Manipulate with reference: " << &data << std::endl;
for (size_t it=0; it < data.size(); ++it)
{
data[it] = value + it;
}
// In a real consumer function we will do much more meaningful operations.
// However, we cannot destruct an object passed in with a reference.
}
Data worker1()
{
Data data;
// Manipulate the Data object.
manipulate_with_reference(data, 3);
return data;
}
Data worker2()
{
Data data = worker1();
// Manipulate the Data object, again.
manipulate_with_reference(data, 8);
return data;
}
int main(int argc, char ** argv)
{
std::cout
<< (bool(IsCopied::instance()) ? "Something" : "Nothing")
<< " is copied" << std::endl;
Data data = worker2();
std::cout
<< (bool(IsCopied::instance()) ? "Something" : "Nothing")
<< " is copied" << std::endl;
return 0;
}
|
Build 01_copy.cpp.#
$ g++ 01_copy.cpp -o 01_copy -std=c++17 -g -O3
$ g++ 01_copy.cpp -o 01_copy -std=c++17 -g -O0
The interaction between movement and copy elision (
02_move.cpp
).#1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 | #include <iostream>
#include <cstdlib>
#include <algorithm>
#include <memory>
class Status
{
public:
static Status & instance()
{
// This is a singleton.
static Status inst;
return inst;
}
bool is_copied() const { return m_copied; }
bool is_moved() const { return m_moved; }
void set_copied() { m_copied = true; }
void set_moved() { m_moved = true; }
private:
Status() : m_copied(false), m_moved(false) {}
bool m_copied;
bool m_moved;
}; /* end class Status */
class Data
{
public:
constexpr const static size_t NELEM = 1024*8;
Data()
{
m_buffer = new int[NELEM];
std::cout << "Data constructed @" << this
<< std::endl;
}
Data(Data const & other)
{
m_buffer = new int[NELEM];
copy_from(other);
std::cout << "Data copied to @" << this
<< " from @" << &other << std::endl;
}
Data & operator=(Data const & other)
{
if (nullptr == m_buffer) { m_buffer = new int[NELEM]; }
copy_from(other);
std::cout << "Data copy assigned to @" << this
<< " from @" << &other << std::endl;
return *this;
}
Data(Data && other)
{
m_buffer = other.m_buffer;
other.m_buffer = nullptr;
std::cout << "Data moved to @" << this
<< " from @" << &other << std::endl;
Status::instance().set_moved();
}
Data & operator=(Data && other)
{
if (m_buffer) { delete[] m_buffer; }
m_buffer = other.m_buffer;
other.m_buffer = nullptr;
std::cout << "Data move assigned to @" << this
<< " from @" << &other << std::endl;
Status::instance().set_moved();
return *this;
}
~Data()
{
if (m_buffer) { delete[] m_buffer; }
std::cout << "Data destructed @" << this << std::endl;
}
size_t size() const { return NELEM; }
int operator[](size_t it) const { return m_buffer[it]; }
int & operator[](size_t it) { return m_buffer[it]; }
bool is_manipulated() const
{
for (size_t it=0; it < size(); ++it)
{
if ((*this)[it] != it) { return false; }
}
return true;
}
private:
void reset()
{
}
void copy_from(Data const & other)
{
for (size_t it=0; it < NELEM; ++it)
{
m_buffer[it] = other.m_buffer[it];
}
Status::instance().set_copied();
}
// A lot of data that we don't want to reconstruct.
int * m_buffer;
}; /* end class Data */
void manipulate_with_reference(Data & data, int value)
{
std::cout << "Manipulate with reference: " << &data << std::endl;
for (size_t it=0; it < data.size(); ++it)
{
data[it] = value + it;
}
// In a real consumer function we will do much more meaningful operations.
// However, we cannot destruct an object passed in with a reference.
}
Data worker1()
{
Data data;
// Manipulate the Data object.
manipulate_with_reference(data, 3);
return data;
}
Data worker2()
{
Data data = worker1();
// Manipulate the Data object, again.
manipulate_with_reference(data, 8);
#ifdef FORCEMOVE
// Explicit move semantics destroys copy elision.
return std::move(data);
#else
return data;
#endif
}
int main(int argc, char ** argv)
{
std::cout
<< "Status:"
<< (bool(Status::instance().is_copied()) ? " copied" : " uncopied")
<< (bool(Status::instance().is_moved()) ? " moved" : " unmoved")
<< std::endl;
Data data = worker2();
std::cout
<< "Status:"
<< (bool(Status::instance().is_copied()) ? " copied" : " uncopied")
<< (bool(Status::instance().is_moved()) ? " moved" : " unmoved")
<< std::endl;
return 0;
}
|
Build 02_move.cpp.#
$ g++ 02_move.cpp -o 02_move -std=c++17 -g -O3
$ g++ 02_move.cpp -o 02_move -std=c++17 -g -O3 -DFORCEMOVE
Concatenate containers (
03_accumulate.cpp
).#1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 | #include <iostream>
#include <cstdlib>
#include <algorithm>
#include <memory>
#include <iterator>
#include <vector>
class Data
{
public:
constexpr const static size_t NELEM = 1024*8;
Data(size_t serial)
: m_serial(serial)
{
m_buffer = new int[NELEM];
initialize();
std::cout << "Data #" << m_serial << " constructed @" << this
<< std::endl;
}
Data(Data const & other)
{
m_serial = other.m_serial;
m_buffer = new int[NELEM];
copy_from(other);
std::cout << "Data #" << m_serial << " copied to @" << this
<< " from @" << &other << std::endl;
}
Data & operator=(Data const & other)
{
m_serial = other.m_serial;
if (nullptr == m_buffer) { m_buffer = new int[NELEM]; }
copy_from(other);
std::cout << "Data #" << m_serial << " copy assigned to @" << this
<< " from @" << &other << std::endl;
return *this;
}
#ifdef MOVENOEXCEPT
Data(Data && other) noexcept
#else // MOVENOEXCEPT
Data(Data && other)
#endif // MOVENOEXCEPT
{
m_serial = other.m_serial;
m_buffer = other.m_buffer;
other.m_buffer = nullptr;
std::cout << "Data #" << m_serial << " moved to @" << this
<< " from @" << &other << std::endl;
}
Data & operator=(Data && other)
{
m_serial = other.m_serial;
if (m_buffer) { delete[] m_buffer; }
m_buffer = other.m_buffer;
other.m_buffer = nullptr;
std::cout << "Data #" << m_serial << " move assigned to @" << this
<< " from @" << &other << std::endl;
return *this;
}
~Data()
{
if (m_buffer) { delete[] m_buffer; }
std::cout << "Data #" << m_serial << " destructed @" << this
<< std::endl;
}
size_t size() const { return NELEM; }
int operator[](size_t it) const { return m_buffer[it]; }
int & operator[](size_t it) { return m_buffer[it]; }
bool is_initialized() const
{
for (size_t it=0; it < size(); ++it)
{
if ((*this)[it] != it) { return false; }
}
return true;
}
private:
void initialize()
{
for (size_t it=0; it < size(); ++it)
{
(*this)[it] = it;
}
}
void copy_from(Data const & other)
{
for (size_t it=0; it < NELEM; ++it)
{
m_buffer[it] = other.m_buffer[it];
}
}
size_t m_serial;
// A lot of data that we don't want to reconstruct.
int * m_buffer;
}; /* end class Data */
std::vector<Data> inner1(size_t start, size_t len)
{
std::cout << "** inner1 begins with " << start << std::endl;
std::vector<Data> ret;
for (size_t it=0; it < len; ++it)
{
Data data(start+it);
ret.emplace_back(std::move(data));
}
return ret;
}
void outer1(size_t len)
{
std::cout << "* outer1 begins" << std::endl;
std::vector<Data> vec;
for (size_t it=0; it < len; ++it)
{
std::cout << std::endl;
std::cout << "* outer1 loop it=" << it << " begins" << std::endl;
std::vector<Data> subvec = inner1(vec.size(), it+1);
std::cout << "* outer1 obtained inner1 at " << vec.size() << std::endl;
vec.insert(
vec.end()
, std::make_move_iterator(subvec.begin())
, std::make_move_iterator(subvec.end())
);
std::cout << "* outer1 inserted subvec.size()=" << subvec.size() << std::endl;
}
std::cout << "* outer1 result.size() = " << vec.size() << std::endl << std::endl;
}
void inner2(size_t start, size_t len, std::vector<Data> & result /* for output */)
{
std::cout << "** inner2 begins with " << start << std::endl;
for (size_t it=0; it < len; ++it)
{
Data data(start+it);
result.emplace_back(std::move(data));
}
}
void outer2(size_t len)
{
std::cout << "* outer2 begins" << std::endl;
std::vector<Data> vec;
for (size_t it=0; it < len; ++it)
{
std::cout << std::endl;
std::cout << "* outer2 loop it=" << it << " begins" << std::endl;
inner2(vec.size(), it+1, vec);
}
std::cout << "* outer2 result.size() = " << vec.size() << std::endl << std::endl;
}
struct Accumulator
{
public:
// This can be called if consumers want the sub-operation one by one, and
// make the code more testable. But it isn't really used in the example.
std::vector<Data> inner1(size_t start, size_t len)
{
std::cout << "** Accumulator::inner1 begins with " << start << std::endl;
std::vector<Data> ret;
ret.reserve(len);
inner2(start, len, ret);
return ret;
}
private:
// Caller does not see this private helper that takes an output argument.
void inner2(size_t start, size_t len, std::vector<Data> & ret)
{
std::cout << "** Accumulator::inner2 begins with " << start << std::endl;
for (size_t it=0; it < len; ++it)
{
Data data(start+it);
ret.emplace_back(std::move(data));
}
}
public:
// This is used when batch operation is in demand.
void outer(size_t len)
{
std::cout << "* Accumulator::outer begins" << std::endl;
result.reserve(len*(len+1)/2);
for (size_t it=0; it < len; ++it)
{
std::cout << std::endl;
std::cout << "* Accumulator::outer loop it=" << it
<< " begins" << std::endl;
// The output argument passed into the private helper is a private
// member datum.
inner2(result.size(), it+1, result);
}
std::cout << "* Accumulator::outer result.size() = "
<< result.size() << std::endl << std::endl;
}
public:
std::vector<Data> result;
}; /* end struct Accumulator */
int main(int argc, char ** argv)
{
#ifndef OTYPE
#define OTYPE 1
#endif
#if OTYPE == 1
outer1(3);
#elif OTYPE == 2
outer2(3);
#elif OTYPE == 3
Accumulator().outer(3);
#endif
}
|
Build 03_accumulate.cpp.#
$ g++ 03_accumulate.cpp -o 03_accumulate -std=c++17 -g -O3 -DOTYPE=1
$ g++ 03_accumulate.cpp -o 03_accumulate -std=c++17 -g -O3 -DMOVENOEXCEPT -DOTYPE=1
$ g++ 03_accumulate.cpp -o 03_accumulate -std=c++17 -g -O3 -DMOVENOEXCEPT -DOTYPE=2
$ g++ 03_accumulate.cpp -o 03_accumulate -std=c++17 -g -O3 -DMOVENOEXCEPT -DOTYPE=3
Variadic template for factory function (
01_factory.cpp
).#1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 | #include <type_traits>
#include <iostream>
#include <cstdlib>
#include <algorithm>
#include <memory>
#include <iterator>
#include <vector>
class Data
: std::enable_shared_from_this<Data>
{
private:
class ctor_passkey {};
public:
constexpr const static size_t NELEM = 1024*8;
/* 'create' only expose some of the constructors */
static std::shared_ptr<Data> create(size_t serial)
{
return std::make_shared<Data>(serial, ctor_passkey());
}
/* 'make' unconditionally forward to every constructor */
template < typename ... Args >
static std::shared_ptr<Data> make(Args && ... args)
{
return std::make_shared<Data>(std::forward<Args>(args) ..., ctor_passkey());
}
Data(size_t serial, ctor_passkey const &)
: m_serial(serial)
{
m_buffer = new int[NELEM];
initialize(0);
std::cout << "Data #" << m_serial << " constructed @" << this
<< "(serial=" << m_serial << ")" << std::endl;
}
Data(size_t serial, int base, ctor_passkey const &)
: m_serial(serial+base)
{
m_buffer = new int[NELEM];
initialize(0);
std::cout << "Data #" << m_serial << " constructed @" << this
<< "(serial=" << m_serial << ")"
<< "(base=" << base << ")" << std::endl;
}
// Proxy to copy and move constructor.
Data(Data const & other, ctor_passkey const &)
: Data(std::forward<Data const &>(other)) {}
Data(Data && other, ctor_passkey const &)
: Data(std::forward<Data &&>(other)) {}
Data(Data const & other)
{
m_serial = other.m_serial;
m_buffer = new int[NELEM];
copy_from(other);
std::cout << "Data #" << m_serial << " copied to @" << this
<< " from @" << &other << std::endl;
}
Data(Data && other) noexcept
{
m_serial = other.m_serial;
m_buffer = other.m_buffer;
other.m_buffer = nullptr;
std::cout << "Data #" << m_serial << " moved to @" << this
<< " from @" << &other << std::endl;
}
// Turn off default constructor.
Data() = delete;
// Turn off assignment operators before we know how they should behave.
Data & operator=(Data const & ) = delete;
Data & operator=(Data &&) = delete;
~Data()
{
if (m_buffer) { delete[] m_buffer; }
std::cout << "Data #" << m_serial << " destructed @" << this << std::endl;
}
size_t size() const { return NELEM; }
int operator[](size_t it) const { return m_buffer[it]; }
int & operator[](size_t it) { return m_buffer[it]; }
bool is_initialized() const
{
for (size_t it=0; it < size(); ++it)
{
if ((*this)[it] != it) { return false; }
}
return true;
}
private:
void initialize(int base)
{
for (size_t it=0; it < size(); ++it)
{
(*this)[it] = base + it;
}
}
void copy_from(Data const & other)
{
for (size_t it=0; it < NELEM; ++it)
{
m_buffer[it] = other.m_buffer[it];
}
}
size_t m_serial;
// A lot of data that we don't want to reconstruct.
int * m_buffer;
}; /* end class Data */
std::vector<std::shared_ptr<Data>> inner1(size_t base, size_t len)
{
std::cout << "** inner1 begins with " << base << std::endl;
std::vector<std::shared_ptr<Data>> ret;
for (size_t it=0; it < len; ++it)
{
std::shared_ptr<Data> data;
if (0 == base)
{
#ifdef USE_CREATE
data = Data::create(it);
#else
data = Data::make(it);
#endif
}
else
{
#ifdef USE_CREATE
data = Data::create(it, base);
#else
data = Data::make(it, base);
#endif
}
ret.emplace_back(data);
}
return ret;
}
void outer1(size_t len)
{
std::cout << "* outer1 begins" << std::endl;
std::vector<std::shared_ptr<Data>> vec;
for (size_t it=0; it < len; ++it)
{
std::cout << std::endl;
std::cout << "* outer1 loop it=" << it << " begins" << std::endl;
std::vector<std::shared_ptr<Data>> subvec = inner1(vec.size(), it+1);
std::cout << "* outer1 obtained inner1 at " << vec.size() << std::endl;
vec.insert(
vec.end()
, std::make_move_iterator(subvec.begin())
, std::make_move_iterator(subvec.end())
);
std::cout << "* outer1 inserted subvec.size()=" << subvec.size() << std::endl;
}
std::cout << "* outer1 result.size() = " << vec.size() << std::endl << std::endl;
#ifdef SHOW_PERFECT_FORWARD
vec.emplace_back(Data::make(*vec[0]));
vec.emplace_back(Data::make(std::move(*vec[1])));
#endif
std::cout << "* outer1 end" << std::endl << std::endl;
}
int main(int argc, char ** argv)
{
outer1(3);
return 0;
}
|
Build 01_factory.cpp.#
$ g++ 01_factory.cpp -o 01_factory -std=c++17 -g -O3 -DUSE_CREATE
$ g++ 01_factory.cpp -o 01_factory -std=c++17 -g -O3
$ g++ 01_factory.cpp -o 01_factory -std=c++17 -g -O3 -DSHOW_PERFECT_FORWARD
C++ lambda (
01_lambda.cpp
).#1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | #include <iostream>
#include <algorithm>
#include <vector>
struct Functor
{
bool operator()(int v)
{
return 0 == v % 23;
}
}; /* end struct Functor */
int main(int argc, char ** argv)
{
std::vector<int> data(63712);
for (size_t i=0 ; i<data.size(); ++i) { data[i] = i;}
std::cout
<< "Number divisible by 23 (count by functor): "
<< std::count_if(data.begin(), data.end(), Functor())
<< std::endl;
std::cout
<< "Number divisible by 23 (count by lambda): "
<< std::count_if(data.begin(), data.end(), [](int v){ return 0 == v%23; })
<< std::endl;
// Demonstrate the similarity between a functor and a lambda.
auto le = [](int v){ return 0 == v%23; };
Functor func;
static_assert(sizeof(le) == sizeof(func));
static_assert(1 == sizeof(le));
static_assert(1 == sizeof(func));
return 0;
}
|
Build 01_lambda.cpp.#
$ g++ 01_lambda.cpp -o 01_lambda -std=c++17 -g -O3
Store a lambda in a variable (
02_stored.cpp
).#1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 | #include <iostream>
#include <algorithm>
#include <vector>
#include <functional>
int main(int argc, char ** argv)
{
std::vector<int> data(63712);
for (size_t i=0 ; i<data.size(); ++i) { data[i] = i;}
std::cout
<< "Number divisible by 23 (count by lambda inline): "
<< std::count_if(data.begin(), data.end(), [](int v){ return 0 == v%23; })
<< std::endl;
auto condition = [](int v){ return 0 == v%23; };
std::cout
<< "Number divisible by 23 (count by lambda in auto): "
<< std::count_if(data.begin(), data.end(), condition)
<< std::endl;
std::function<bool (int)> condition_function = [](int v){ return 0 == v%23; };
std::cout
<< "Number divisible by 23 (count by lambda in std::function): "
<< std::count_if(data.begin(), data.end(), condition_function)
<< std::endl;
#ifdef SHOW_DIFF
// Difference between lambda and std::function.
std::cout
<< std::endl
<< "The differences between lambda and std::function"
<< std::endl;
std::cout
<< "type name of lambda: "
<< typeid(condition).name() << std::endl;
std::cout
<< "type name of std::function: "
<< typeid(condition_function).name() << std::endl;
std::cout
<< "size of lambda: "
<< sizeof(condition) << std::endl;
std::cout
<< "size of std::function: "
<< sizeof(condition_function) << std::endl;
#endif
return 0;
}
|
Build 02_stored.cpp.#
$ g++ 02_stored.cpp -o 02_stored -std=c++17 -g -O3
$ g++ 02_stored.cpp -o 02_stored -std=c++17 -g -O3 -DSHOW_DIFF
Store a lambda in a variable, demangled version
(
02_stored_demangle.cpp
).#1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 | #include <iostream>
#include <algorithm>
#include <vector>
#include <memory>
// NOTE: This isn't guaranteed to work in every compiler.
#include <cxxabi.h>
std::string demangle(const char* name)
{
// An arbitrary value to eliminate the compiler warning.
int status = -1;
std::unique_ptr<char, void(*)(void*)> res(
abi::__cxa_demangle(name, NULL, NULL, &status),
std::free
);
return (status==0) ? res.get() : name;
}
int main(int argc, char ** argv)
{
std::vector<int> data(63712);
for (size_t i=0 ; i<data.size(); ++i) { data[i] = i;}
std::cout
<< "Number divisible by 23 (count by inline lambda): "
<< std::count_if(data.begin(), data.end(), [](int v){ return 0 == v%23; })
<< std::endl;
auto condition = [](int v){ return 0 == v%23; };
std::cout
<< "Number divisible by 23 (count by stored lambda): "
<< std::count_if(data.begin(), data.end(), condition)
<< std::endl;
std::cout << "type name of condition: " << demangle(typeid(condition).name()) << std::endl;
return 0;
}
|
Build 02_stored_demangle.cpp.#
$ g++ 02_stored_demangle.cpp -o 02_stored_demangle -std=c++17 -g -O3
Closure example (
03_closure.cpp
).#1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 | #include <iostream>
#include <algorithm>
#include <vector>
#include <functional>
int main(int argc, char ** argv)
{
std::vector<int> data(63712);
for (size_t i=0 ; i<data.size(); ++i) { data[i] = i;}
int divisor = 23;
#if WRONG_CAPTURE
std::cout
<< "Count (wrong capture): "
<< std::count_if(data.begin(), data.end(),
[](int v){ return 0 == v%divisor; })
<< " (divisor: " << divisor << ")"
<< std::endl;
#endif
std::cout
<< "Count (lambda explicitly capture by value): "
<< std::count_if(data.begin(), data.end(),
[divisor](int v){ return 0 == v%divisor; })
<< " (divisor: " << divisor << ")"
<< std::endl;
std::cout
<< "Count (lambda implicitly capture by value): "
<< std::count_if(data.begin(), data.end(),
[=](int v){ return 0 == v%divisor; })
<< " (divisor: " << divisor << ")"
<< std::endl;
std::cout
<< "Count (lambda explicitly capture by reference): "
<< std::count_if(data.begin(), data.end(),
[&divisor](int v){ divisor = 10; return 0 == v%divisor; })
<< " (divisor: " << divisor << ")"
<< std::endl;
return 0;
}
|
Build 03_closure.cpp.#
$ g++ 03_closure.cpp -o 03_closure -std=c++17 -g -O3 -DWRONG_CAPTURE
$ g++ 03_closure.cpp -o 03_closure -std=c++17 -g -O3