listings-Chap13-README-onepage.md
Listings of Chap13.docx
This is the list of listings on one page. You can also view a linked summary.
Listing 13.1: You define a namespace with “namespace”.
Book listing lst-0001-book.cpp:
// https://godbolt.org/z/qo6W3bh5d
#include <string>
#include <iostream> // ostream, cout
namespace plant {
class Tree {
std::string name_;
public:
explicit Tree(const std::string_view name) : name_{name} {}
void print(std::ostream& os) const { os << name_; }
};
std::ostream& operator<<(std::ostream& os, const Tree& arg)
{ arg.print(os); return os; }
using ConiferTree = Tree; // for future extensions …
using BroadleafTree = Tree; // … provide for
namespace exampleNames { // embedded namespace
std::string oakName = "Oak";
std::string beechName = "Beech";
std::string firName = "Fir";
} // end namespace exampleNames
} // end namespace plant
int main() { // main must not be in a namespace
using namespace plant::exampleNames; // make all example names available
plant::ConiferTree fir{ firName };
plant::BroadleafTree oak{ oakName };
fir.print(std::cout); std::cout << "\n";
using plant::operator<<; // without it 'cout << oak' won't work
std::cout << oak << "\n";
}
Godbolt Listing lst-0001-godb.cpp, https://godbolt.org/z/qo6W3bh5d:
//#(compile) c++; compiler:g141; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/qo6W3bh5d
#include <string>
#include <iostream> // ostream, cout
namespace plant {
class Tree {
std::string name_;
public:
explicit Tree(const std::string_view name) : name_{name} {}
void print(std::ostream& os) const { os << name_; }
};
std::ostream& operator<<(std::ostream& os, const Tree& arg)
{ arg.print(os); return os; }
using ConiferTree = Tree; // for future extensions …
using BroadleafTree = Tree; // … provide for
namespace exampleNames { // embedded namespace
std::string oakName = "Oak";
std::string beechName = "Beech";
std::string firName = "Fir";
} // end namespace exampleNames
} // end namespace plant
int main() { // main must not be in a namespace
using namespace plant::exampleNames; // make all example names available
plant::ConiferTree fir{ firName };
plant::BroadleafTree oak{ oakName };
fir.print(std::cout); std::cout << "\n";
using plant::operator<<; // without it 'cout << oak' won't work
std::cout << oak << "\n";
}
Listing 13.2: In separate namespaces, you can define the same operators.
Book listing lst-0005-book.cpp:
namespace plant {
// … as before …
std::ostream& operator<<(std::ostream&, const Tree&) {…};
namespace debug {
std::ostream& operator<<(std::ostream&, const Tree&) {…};
}
}
plant::Tree tree{"MyTree"};
void run() {
using namespace plant;
cout << tree << "\n";
}
void diagnostic() {
using namespace plant::debug;
cout << tree << "\n";
}
int main() {
run();
diagnostic();
}
Listing 13.3: An anonymous namespace makes definitions local to the current file.
Book listing lst-0006-book.cpp:
// https://godbolt.org/z/e3d55zvT8
// modul.hpp
#include <string>
#include <iostream>
namespace plant {
class Tree {
std::string name_;
public:
explicit Tree(const std::string_view name);
void print(std::ostream& os) const;
};
std::ostream& operator<<(std::ostream& os, const Tree& arg);
}
// modul.cpp
#include "modul.hpp"
namespace { // anonymous namespace
std::string PREFIX = "TREE:";
void printInfo(std::ostream& os) {
os << "Author: Torsten T. Will\n";
}
}
bool debug = false; // global, no namespace
namespace plant {
Tree::Tree(const std::string_view name)
: name_{name} {}
void Tree::print(std::ostream& os) const {
os << PREFIX << name_;
}
std::ostream& operator<<(std::ostream& os, const Tree& arg) {
if(debug) printInfo(os);
arg.print(os); return os;
}
}
// main.cpp
#include "modul.hpp"
int main() {
plant::Tree x{"x"};
x.print(std::cout); std::cout << "\n";
}
Godbolt Listing lst-0006-godb.cpp, https://godbolt.org/z/e3d55zvT8:
//#(compile) c++; compiler:g141; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/e3d55zvT8
// modul.hpp
#include <string>
#include <iostream>
namespace plant {
class Tree {
std::string name_;
public:
explicit Tree(const std::string_view name);
void print(std::ostream& os) const;
};
std::ostream& operator<<(std::ostream& os, const Tree& arg);
}
// modul.cpp
#include "modul.hpp"
namespace { // anonymous namespace
std::string PREFIX = "TREE:";
void printInfo(std::ostream& os) {
os << "Author: Torsten T. Will\n";
}
}
bool debug = false; // global, no namespace
namespace plant {
Tree::Tree(const std::string_view name)
: name_{name} {}
void Tree::print(std::ostream& os) const {
os << PREFIX << name_;
}
std::ostream& operator<<(std::ostream& os, const Tree& arg) {
if(debug) printInfo(os);
arg.print(os); return os;
}
}
// main.cpp
#include "modul.hpp"
int main() {
plant::Tree x{"x"};
x.print(std::cout); std::cout << "\n";
}
GodboltId:zfYzPjqrW
Book listing lst-0007-book.cpp:
// https://godbolt.org/z/zfYzPjqrW
// modul.cpp
#include "modul.hpp"
static std::string PREFIX = "TREE:";
static void printInfo(std::ostream& os) {
os << "Author: Torsten T. Will\n";
}
bool debug = false;
// rest as before
Godbolt Listing lst-0007-godb.cpp, https://godbolt.org/z/zfYzPjqrW:
//#(compile) c++; compiler:g141; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/zfYzPjqrW
// modul.cpp
#include "modul.hpp"
static std::string PREFIX = "TREE:";
static void printInfo(std::ostream& os) {
os << "Author: Torsten T. Will\n";
}
bool debug = false;
// rest as before
Listing 13.4: All instances share their “static” data fields and methods.
Book listing lst-0009-book.cpp:
// https://godbolt.org/z/n4e8xdEGj
#include <iostream> // cout
#include <string>
using std::string;
class Tree {
static size_t countConstructed_;
static size_t countDestructed_;
string kind_;
Tree(string kind) : kind_{kind} // private constructor
{ ++countConstructed_; }
public:
Tree(const Tree& o) : kind_{o.kind_}
{ ++countConstructed_; }
string getKind() const { return kind_; }
~Tree() { ++countDestructed_; }
static Tree create(string kind) { return Tree{kind}; }
static void stats(std::ostream& os) {
os << "Constructed:+" << countConstructed_
<< " Destructed:-" << countDestructed_ << "\n";
}
};
size_t Tree::countConstructed_ = 0;
size_t Tree::countDestructed_ = 0;
int main() {
Tree birch = Tree::create("Birch");
for(auto kind : {"Ash", "Yew", "Oak"}) {
Tree temp = Tree::create(kind);
std::cout << temp.getKind() << "\n";
}
Tree::stats(std::cout);
}
Godbolt Listing lst-0009-godb.cpp, https://godbolt.org/z/n4e8xdEGj:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/n4e8xdEGj
#include <iostream> // cout
#include <string>
using std::string;
class Tree {
static size_t countConstructed_;
static size_t countDestructed_;
string kind_;
Tree(string kind) : kind_{kind} // private constructor
{ ++countConstructed_; }
public:
Tree(const Tree& o) : kind_{o.kind_}
{ ++countConstructed_; }
string getKind() const { return kind_; }
~Tree() { ++countDestructed_; }
static Tree create(string kind) { return Tree{kind}; }
static void stats(std::ostream& os) {
os << "Constructed:+" << countConstructed_
<< " Destructed:-" << countDestructed_ << "\n";
}
};
size_t Tree::countConstructed_ = 0;
size_t Tree::countDestructed_ = 0;
int main() {
Tree birch = Tree::create("Birch");
for(auto kind : {"Ash", "Yew", "Oak"}) {
Tree temp = Tree::create(kind);
std::cout << temp.getKind() << "\n";
}
Tree::stats(std::cout);
}
GodboltId:b9arcEMM1
Book listing lst-0011-book.cpp:
// https://godbolt.org/z/b9arcEMM1
constinit auto SZ = 10*1000-1; // global variable
size_t autoincrement() {
static constinit size_t i = 0; // local static variable
return i++;
}
class BraitenbergVehicle {
inline static constinit size_t count_ = 0; // class variable
public:
size_t id_;
BraitenbergVehicle() : id_{++count_} {}
~BraitenbergVehicle() { --count_; }
};
Godbolt Listing lst-0011-godb.cpp, https://godbolt.org/z/b9arcEMM1:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/b9arcEMM1
constinit auto SZ = 10*1000-1; // global variable
size_t autoincrement() {
static constinit size_t i = 0; // local static variable
return i++;
}
class BraitenbergVehicle {
inline static constinit size_t count_ = 0; // class variable
public:
size_t id_;
BraitenbergVehicle() : id_{++count_} {}
~BraitenbergVehicle() { --count_; }
};
Listing 13.5: A local static variable is initialized once and reused thereafter.
Book listing lst-0012-book.cpp:
// https://godbolt.org/z/h5qond6db
#include <iostream> // cout
class Keyboard {
Keyboard(const Keyboard&) = delete; // no copy
const size_t nr_; // current number
public:
static inline size_t count_ = 0; // counts created instances
explicit Keyboard() : nr_{count_++} {
std::cout << " Keyboard().nr:"<<nr_<<"\n";
}
};
Keyboard& getKeyboard() {
std::cout << " getKeyboard()\n";
static Keyboard keyboard{}; // static local variable
return keyboard;
}
void func() {
std::cout << "kbFunc...\n";
Keyboard& kbFunc = getKeyboard();
}
int main() {
std::cout << "kbA...\n";
Keyboard& kbA = getKeyboard();
func();
std::cout << "kbB...\n";
Keyboard& kbB = getKeyboard();
std::cout << "count:" << Keyboard::count_ << "\n";
}
Godbolt Listing lst-0012-godb.cpp, https://godbolt.org/z/h5qond6db:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/h5qond6db
#include <iostream> // cout
class Keyboard {
Keyboard(const Keyboard&) = delete; // no copy
const size_t nr_; // current number
public:
static inline size_t count_ = 0; // counts created instances
explicit Keyboard() : nr_{count_++} {
std::cout << " Keyboard().nr:"<<nr_<<"\n";
}
};
Keyboard& getKeyboard() {
std::cout << " getKeyboard()\n";
static Keyboard keyboard{}; // static local variable
return keyboard;
}
void func() {
std::cout << "kbFunc...\n";
Keyboard& kbFunc = getKeyboard();
}
int main() {
std::cout << "kbA...\n";
Keyboard& kbA = getKeyboard();
func();
std::cout << "kbB...\n";
Keyboard& kbB = getKeyboard();
std::cout << "count:" << Keyboard::count_ << "\n";
}
Listing 13.6: The Meyers Singleton.
Book listing lst-0013-book.cpp:
Keyboard& getKeyboard() {
cout << " getKeyboard()\n”;
static Keyboard keyboard{}; // static local variable
return keyboard;
}
Listing 13.7: The identifiers of an inline namespace also go into its surrounding namespace.
Book listing lst-0014-book.cpp:
// https://godbolt.org/z/115M1csEE
#include <iostream>
namespace mylib {
namespace v1 {
int version() { return 1; }
}
inline namespace v2 { // current version
int version() { return 2; }
}
}
int main() {
std::cout << "Version " << mylib::version() << "\n”; // Output: 2
std::cout << "Version " << mylib::v1::version() << "\n”; // Output: 1
std::cout << "Version " << mylib::v2::version() << "\n”; // Output: 2
}
Godbolt Listing lst-0014-godb.cpp, https://godbolt.org/z/115M1csEE:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/115M1csEE
#include <iostream>
namespace mylib {
namespace v1 {
int version() { return 1; }
}
inline namespace v2 { // current version
int version() { return 2; }
}
}
int main() {
std::cout << "Version " << mylib::version() << "\n”; // Output: 2
std::cout << "Version " << mylib::v1::version() << "\n”; // Output: 1
std::cout << "Version " << mylib::v2::version() << "\n”; // Output: 2
}
GodboltId:WTWxYa3rd
Book listing lst-0024-book.cpp:
// https://godbolt.org/z/WTWxYa3rd
class Widget {
unsigned x = 0, y = 0, w = 0, h = 0; // for example
public:
unsigned getLeft() const;
unsigned getTop() const;
unsigned getRight() const;
unsigned getBottom() const;
void setWidth(unsigned w);
void setHeight(unsigned h);
};
Godbolt Listing lst-0024-godb.cpp, https://godbolt.org/z/WTWxYa3rd:
//#(execute) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/WTWxYa3rd
class Widget {
unsigned x = 0, y = 0, w = 0, h = 0; // for example
public:
unsigned getLeft() const;
unsigned getTop() const;
unsigned getRight() const;
unsigned getBottom() const;
void setWidth(unsigned w);
void setHeight(unsigned h);
};
Listing 13.8: Local constants of a file fit well into an anonymous namespace.
Book listing lst-0029-book.cpp:
// https://godbolt.org/z/bxPaz9aW5
#include <vector>
namespace { // anonymous namespace for constants
const unsigned DATA_SIZE = 100; /* number of elements in data */
const double LIMIT = 999.999; /* max value during initialization */
};
std::vector<int> createData() {
std::vector<int> result(DATA_SIZE);
double currVal = 1.0;
for(auto &elem : result) {
elem = currVal;
currVal *= 2; // next value is larger
if(currVal > LIMIT) {
currVal = LIMIT; // no value should be larger
}
}
return result;
}
Godbolt Listing lst-0029-godb.cpp, https://godbolt.org/z/bxPaz9aW5:
//#(compile) c++; compiler:g141; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/bxPaz9aW5
#include <vector>
namespace { // anonymous namespace for constants
const unsigned DATA_SIZE = 100; /* number of elements in data */
const double LIMIT = 999.999; /* max value during initialization */
};
std::vector<int> createData() {
std::vector<int> result(DATA_SIZE);
double currVal = 1.0;
for(auto &elem : result) {
elem = currVal;
currVal *= 2; // next value is larger
if(currVal > LIMIT) {
currVal = LIMIT; // no value should be larger
}
}
return result;
}
GodboltId:fM4nsx9GP
Book listing lst-0030-book.cpp:
// https://godbolt.org/z/fM4nsx9GP
struct Widget {
int num_ = 0;
void setNumber(int x) { // a non-const method
num_=x;
}
};
Widget createWidget() { // Return by value
Widget result{}; // Create
return result;
}
int main() {
Widget w = createWidget(); // Return by value creates a copy
w.setNumber(100); // changing is naturally okay, w is non-const
}
Godbolt Listing lst-0030-godb.cpp, https://godbolt.org/z/fM4nsx9GP:
//#(compile) c++; compiler:g141; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/fM4nsx9GP
struct Widget {
int num_ = 0;
void setNumber(int x) { // a non-const method
num_=x;
}
};
Widget createWidget() { // Return by value
Widget result{}; // Create
return result;
}
int main() {
Widget w = createWidget(); // Return by value creates a copy
w.setNumber(100); // changing is naturally okay, w is non-const
}
Listing 13.9: Although the return type is marked with ‘const’ here, it has no effect because it is always copied.
Book listing lst-0031-book.cpp:
// https://godbolt.org/z/98x3YsnKc
const Widget createWidget() { // return as const value
Widget result{};
return result;
}
int main() {
Widget w = createWidget(); // copied into new non-const w
w.setNumber(100); // w is non-const, changing is okay
}
Godbolt Listing lst-0031-godb.cpp, https://godbolt.org/z/98x3YsnKc:
//#(compile) c++; compiler:g141; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/98x3YsnKc
const Widget createWidget() { // return as const value
Widget result{};
return result;
}
int main() {
Widget w = createWidget(); // copied into new non-const w
w.setNumber(100); // w is non-const, changing is okay
}
Listing 13.10: Constant references in returns.
Book listing lst-0032-book.cpp:
// https://godbolt.org/z/3EG1ovcev
#include <string>
#include <string_view>
using std::string; using std::string_view;
class Widget {
string name_ = "";
public:
void setName(string_view newName) {
name_ = newName;
}
const string& getName() const { // const& return
return name_;
}
};
int main() {
Widget w{};
w.setName("Title");
string name1 = w.getName(); // new string, thus a copy
name1.clear(); // you are allowed to modify the copy again
const string& name2 = w.getName(); // const reference to internal string name_
/* name2.clear(); */ // name2 is const, so it doesn't work
string& name3 = w.getName(); // (ERR) Function returns const&, not &.
auto name4 = w.getName(); // identical to name1
const auto& name5 = w.getName(); // identical to name2
}
Godbolt Listing lst-0032-godb.cpp, https://godbolt.org/z/3EG1ovcev:
//#(compile) c++; compiler:g141; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/3EG1ovcev
#include <string>
#include <string_view>
using std::string; using std::string_view;
class Widget {
string name_ = "";
public:
void setName(string_view newName) {
name_ = newName;
}
const string& getName() const { // const& return
return name_;
}
};
int main() {
Widget w{};
w.setName("Title");
string name1 = w.getName(); // new string, thus a copy
name1.clear(); // you are allowed to modify the copy again
const string& name2 = w.getName(); // const reference to internal string name_
/* name2.clear(); */ // name2 is const, so it doesn't work
string& name3 = w.getName(); // (ERR) Function returns const&, not &.
auto name4 = w.getName(); // identical to name1
const auto& name5 = w.getName(); // identical to name2
}
Listing 13.11: References can be returned as constant and nonconstant.
Book listing lst-0033-book.cpp:
// https://godbolt.org/z/9MTj3rP5d
#include <string>
#include <iostream>
using std::string; using std::cout;
class Widget {
string name_{};
public:
const string& readName() const; // const&-return, const-method
string& getName(); // &-return
};
const string& Widget::readName() const { return name_; }
string& Widget::getName() { return name_; }
int main() {
Widget w{};
const string& readonly = w.readName(); // const&, immutable
cout << "Name: " << readonly << "\n"; // still "" empty.
string& readwrite = w.getName(); // &, mutable
readwrite.append("attached"); // also changes name_ and readonly
cout << "Name via readwrite: " << readwrite << "\n"; // "attached"
cout << "Name via readonly: " << readonly << "\n"; // also "attached"
}
Godbolt Listing lst-0033-godb.cpp, https://godbolt.org/z/9MTj3rP5d:
//#(compile) c++; compiler:g141; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/9MTj3rP5d
#include <string>
#include <iostream>
using std::string; using std::cout;
class Widget {
string name_{};
public:
const string& readName() const; // const&-return, const-method
string& getName(); // &-return
};
const string& Widget::readName() const { return name_; }
string& Widget::getName() { return name_; }
int main() {
Widget w{};
const string& readonly = w.readName(); // const&, immutable
cout << "Name: " << readonly << "\n"; // still "" empty.
string& readwrite = w.getName(); // &, mutable
readwrite.append("attached"); // also changes name_ and readonly
cout << "Name via readwrite: " << readwrite << "\n"; // "attached"
cout << "Name via readonly: " << readonly << "\n"; // also "attached"
}
GodboltId:4dnTs4vPx
Book listing lst-0036-book.cpp:
// https://godbolt.org/z/4dnTs4vPx
namespace {
const int MAX_A = 12; // the same as MAX_B, but no static needed
}
static const int MAX_B = 10; // in the global namespace
struct Data {
static const int SIZE = 14; // as a data field in a class
};
void func() {
static const int LIMIT = 16; // as a local constant
}
Godbolt Listing lst-0036-godb.cpp, https://godbolt.org/z/4dnTs4vPx:
//#(compile) c++; compiler:g141; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/4dnTs4vPx
namespace {
const int MAX_A = 12; // the same as MAX_B, but no static needed
}
static const int MAX_B = 10; // in the global namespace
struct Data {
static const int SIZE = 14; // as a data field in a class
};
void func() {
static const int LIMIT = 16; // as a local constant
}
Listing 13.12: Some expressions must be known at compile time.
Book listing lst-0037-book.cpp:
// https://godbolt.org/z/E6MWxY1f7
#include <array>
int main() {
std::array<int, 5> arr5{}; // literal and thus a constant expression
std::array<int, 2+3> arr23{}; // 2+3 can be evaluated by the compiler
const size_t SIZE = 5; // defines a constant
std::array<int, SIZE> arrSC{}; // can often be used by the compiler
size_t size = 7;
std::array<int,size> arrVar{}; // you cannot use a variable
}
Godbolt Listing lst-0037-godb.cpp, https://godbolt.org/z/E6MWxY1f7:
//#(compile) c++; compiler:g141; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/E6MWxY1f7
#include <array>
int main() {
std::array<int, 5> arr5{}; // literal and thus a constant expression
std::array<int, 2+3> arr23{}; // 2+3 can be evaluated by the compiler
const size_t SIZE = 5; // defines a constant
std::array<int, SIZE> arrSC{}; // can often be used by the compiler
size_t size = 7;
std::array<int,size> arrVar{}; // you cannot use a variable
}
Listing 13.13: Whether the compiler can use a constant in a constant expression is not always immediately apparent.
Book listing lst-0038-book.cpp:
// https://godbolt.org/z/xPzcWPdMa
#include <array>
struct Data {
static const size_t LATE; // declare constant
static const size_t EARLY; // declare constant
};
void func() {
int x = Data::LATE; // use constant
}
const size_t Data::EARLY = 10; // define constant
std::array<int, Data::EARLY> arrEARLY {}; // use constant
std::array<int, Data::LATE> arrLATE {}; // (ERR) use constant
const size_t Data::LATE = 10; // define constant
int main() {
func();
}
Godbolt Listing lst-0038-godb.cpp, https://godbolt.org/z/xPzcWPdMa:
//#(compile) c++; compiler:g141; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/xPzcWPdMa
#include <array>
struct Data {
static const size_t LATE; // declare constant
static const size_t EARLY; // declare constant
};
void func() {
int x = Data::LATE; // use constant
}
const size_t Data::EARLY = 10; // define constant
std::array<int, Data::EARLY> arrEARLY {}; // use constant
std::array<int, Data::LATE> arrLATE {}; // (ERR) use constant
const size_t Data::LATE = 10; // define constant
int main() {
func();
}
Listing 13.14: With “constexpr”, the compiler sees when an expression is not computable early.
Book listing lst-0040-book.cpp:
struct Data {
static constexpr size_t LATE; // (ERR) does not work without direct initialization
static constexpr size_t EARLY = 10;
};
constexpr size_t Data::LATE = 10; // (ERR) with constexpr, definition is different
GodboltId:Yv85s9T6v
Book listing lst-0041-book.cpp:
// https://godbolt.org/z/Yv85s9T6v
constexpr size_t doubleIfTooSmall1(size_t value) {
return value < 100 ? value*2 : value; // returns double if less than 100
}
std::array<int, doubleIfTooSmall1(50)> arr {};
Godbolt Listing lst-0041-godb.cpp, https://godbolt.org/z/Yv85s9T6v:
//#(compile) c++; compiler:g141; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/Yv85s9T6v
constexpr size_t doubleIfTooSmall1(size_t value) {
return value < 100 ? value*2 : value; // returns double if less than 100
}
std::array<int, doubleIfTooSmall1(50)> arr {};
Listing 13.15: With “if constexpr”, you can decide at compile time what code will be executed.
Book listing lst-0044-book.cpp:
// https://godbolt.org/z/zMbnYzo17
template<typename T>
auto deref(T t) {
if constexpr (std::is_pointer_v<T>) {
return *t;
} else {
return t;
}
}
int main() {
int i = 42;
std::cout << deref(i) << '\n'; // directly the value
auto p = std::make_unique<int>(73);
std::cout << deref(p.get()) << '\n'; // dereferenced pointer
}
Godbolt Listing lst-0044-godb.cpp, https://godbolt.org/z/zMbnYzo17:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/zMbnYzo17
template<typename T>
auto deref(T t) {
if constexpr (std::is_pointer_v<T>) {
return *t;
} else {
return t;
}
}
int main() {
int i = 42;
std::cout << deref(i) << '\n'; // directly the value
auto p = std::make_unique<int>(73);
std::cout << deref(p.get()) << '\n'; // dereferenced pointer
}
Listing 13.16: “if constexpr” also works with “else”.
Book listing lst-0045-book.cpp:
// https://godbolt.org/z/eo468MvMo
#include <iostream>
#include <string>
struct S {
int n;
std::string s;
float d;
};
template <std::size_t N> auto& get(S& s) {
if constexpr (N == 0) return s.n;
else if constexpr (N == 1) return s.s;
else if constexpr (N == 2) return s.d;
}
int main() {
S obj { 0, "hello", 10.0f };
std::cout << get<0>(obj) << ", " << get<1>(obj) << "\n”; // Output: 0, hello
}
Godbolt Listing lst-0045-godb.cpp, https://godbolt.org/z/eo468MvMo:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/eo468MvMo
#include <iostream>
#include <string>
struct S {
int n;
std::string s;
float d;
};
template <std::size_t N> auto& get(S& s) {
if constexpr (N == 0) return s.n;
else if constexpr (N == 1) return s.s;
else if constexpr (N == 2) return s.d;
}
int main() {
S obj { 0, "hello", 10.0f };
std::cout << get<0>(obj) << ", " << get<1>(obj) << "\n”; // Output: 0, hello
}
GodboltId:44KMf1fWr
Book listing lst-0046-book.cpp:
// https://godbolt.org/z/44KMf1fWr
template<auto N>
constexpr auto fibonacci() {
if constexpr (N>=2) {
return fibonacci<N-1>() + fibonacci<N-2>();
} else {
return N;
}
}
int main() {
std::cout << fibonacci<10>() << '\n'; // Output: 55
std::cout << fibonacci<20>() << '\n'; // Output: 6765
}
Godbolt Listing lst-0046-godb.cpp, https://godbolt.org/z/44KMf1fWr:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/44KMf1fWr
template<auto N>
constexpr auto fibonacci() {
if constexpr (N>=2) {
return fibonacci<N-1>() + fibonacci<N-2>();
} else {
return N;
}
}
int main() {
std::cout << fibonacci<10>() << '\n'; // Output: 55
std::cout << fibonacci<20>() << '\n'; // Output: 6765
}
Listing 13.17: With “consteval”, you can execute functions at compile time.
Book listing lst-0047-book.cpp:
// https://godbolt.org/z/v3x7nGs3f
int get_input() {
return 50; // or read something from a file or so
}
constexpr auto calculate_1(int input) {
return input * 2;
}
consteval auto calculate_2(int input) {
return input * 2;
}
int main() {
int input = get_input();
auto a = calculate_1(77); // at compile time … maybe computable
auto b = calculate_1(input); // … computable, but valid
auto c = calculate_2(77); // … computable
auto d = calculate_2(input); // (ERR) … not computable, invalid
}
Godbolt Listing lst-0047-godb.cpp, https://godbolt.org/z/v3x7nGs3f:
//#(compile) c++; compiler:g141; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/v3x7nGs3f
int get_input() {
return 50; // or read something from a file or so
}
constexpr auto calculate_1(int input) {
return input * 2;
}
consteval auto calculate_2(int input) {
return input * 2;
}
int main() {
int input = get_input();
auto a = calculate_1(77); // at compile time … maybe computable
auto b = calculate_1(input); // … computable, but valid
auto c = calculate_2(77); // … computable
auto d = calculate_2(input); // (ERR) … not computable, invalid
}
Listing 13.18: Even more complex functions can be computed at compile time with “consteval”.
Book listing lst-0048-book.cpp:
// https://godbolt.org/z/Wbr7n8M4q
#include <iostream>
#include <array>
constexpr bool isPrime(int n) { // computable at compile-time
if(n < 2) return false; // 0, 1 are not prime
for (int i = 2; i*i <= n; i += i>2 ? 2 : 1) { // 2,3,5,7,9,11,13,15…
if (n % i == 0) return false;
}
return n > 1; // for 0 and 1
}
template<int Num>
consteval std::array<int, Num> primeNumbers() { // only at compile-time
std::array<int, Num> primes{};
int idx = 0;
for (int val = 1; idx < Num; ++val) {
if (isPrime(val)) primes[idx++] = val;
}
return primes;
}
int main() {
// initialize with prime numbers
auto primes = primeNumbers<100>(); // 1000000 doesn't work
for (auto v : primes) {
std::cout << v << ' ';
}
std::cout << '\n';
}
Godbolt Listing lst-0048-godb.cpp, https://godbolt.org/z/Wbr7n8M4q:
//#(compile) c++; compiler:g141; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/Wbr7n8M4q
#include <iostream>
#include <array>
constexpr bool isPrime(int n) { // computable at compile-time
if(n < 2) return false; // 0, 1 are not prime
for (int i = 2; i*i <= n; i += i>2 ? 2 : 1) { // 2,3,5,7,9,11,13,15…
if (n % i == 0) return false;
}
return n > 1; // for 0 and 1
}
template<int Num>
consteval std::array<int, Num> primeNumbers() { // only at compile-time
std::array<int, Num> primes{};
int idx = 0;
for (int val = 1; idx < Num; ++val) {
if (isPrime(val)) primes[idx++] = val;
}
return primes;
}
int main() {
// initialize with prime numbers
auto primes = primeNumbers<100>(); // 1000000 doesn't work
for (auto v : primes) {
std::cout << v << ' ';
}
std::cout << '\n';
}
Listing 13.19: The compiler determines whether the call can be evaluated at compile time in the given context.
Book listing lst-0049-book.cpp:
// https://godbolt.org/z/7KWqTPo1K
#include <iostream> // cout
constexpr int get_value() {
if consteval {
return 42;
} else {
return 668;
}
}
int main() {
auto a = get_value();
std::cout << a << '\n'; // Output: 668
constexpr auto b = get_value();
std::cout << b << '\n'; // Output: 42
}
Godbolt Listing lst-0049-godb.cpp, https://godbolt.org/z/7KWqTPo1K:
//#(compile) c++; compiler:g132; options:"-std=c++23"; libs:-
// https://godbolt.org/z/7KWqTPo1K
#include <iostream> // cout
constexpr int get_value() {
if consteval {
return 42;
} else {
return 668;
}
}
int main() {
auto a = get_value();
std::cout << a << '\n'; // Output: 668
constexpr auto b = get_value();
std::cout << b << '\n'; // Output: 42
}
Listing 13.20: “mutable” makes a data field in const methods mutable.
Book listing lst-0051-book.cpp:
// https://godbolt.org/z/sPorKnEbd
#include <iostream>
class Data {
int value_;
mutable size_t getCount_{0};
public:
explicit Data(int v) : value_{v} { }
~Data() {
std::cout << "get was used " << getCount_ << " times\n";
}
int get() const {
++getCount_;
return value_;
}
};
int main() {
Data d{42};
for(int i=0; i<10; ++i) { d.get(); }
} // Output: get was used 10 times
Godbolt Listing lst-0051-godb.cpp, https://godbolt.org/z/sPorKnEbd:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/sPorKnEbd
#include <iostream>
class Data {
int value_;
mutable size_t getCount_{0};
public:
explicit Data(int v) : value_{v} { }
~Data() {
std::cout << "get was used " << getCount_ << " times\n";
}
int get() const {
++getCount_;
return value_;
}
};
int main() {
Data d{42};
for(int i=0; i<10; ++i) { d.get(); }
} // Output: get was used 10 times
Listing 13.21: “const” with containers.
Book listing lst-0052-book.cpp:
// https://godbolt.org/z/GE5v6Ea8x
#include <map>
#include <string>
using std::map; using std::string;
struct MyClass {
bool isFound(const map<int,string> &dict, // immutable input parameter.
const int &key, // likewise
string &result // output parameter: not const
) const // instance of MyClass const
{
const map<int,string>::const_iterator where // reference and value fixed
= dict.find(key);
if(where == end(dict)) {
return false;
} else {
result = where->second;
return true;
}
}
};
Godbolt Listing lst-0052-godb.cpp, https://godbolt.org/z/GE5v6Ea8x:
//#(execute) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/GE5v6Ea8x
#include <map>
#include <string>
using std::map; using std::string;
struct MyClass {
bool isFound(const map<int,string> &dict, // immutable input parameter.
const int &key, // likewise
string &result // output parameter: not const
) const // instance of MyClass const
{
const map<int,string>::const_iterator where // reference and value fixed
= dict.find(key);
if(where == end(dict)) {
return false;
} else {
result = where->second;
return true;
}
}
};
Listing 13.22: x and y can somehow be changed from outside.
Book listing lst-0053-book.cpp:
#include <iostream>
#include <chrono> // milliseconds
#include <thread> // this_thread::sleep
struct Pos {
volatile int x;
volatile int y;
};
Pos pos{};
// defined somewhere else:
int installMouseDriver(Pos *p);
constexpr auto DELAY = std::chrono::milliseconds(100);
constexpr auto LOOPS = 30; // 30*100ms = 3s
int main() {
installMouseDriver( &pos ); // MouseDriver updates x and y
for(int i=0; i<LOOPS; ++i) {
std::cout << "mouse at ("<<pos.x<<","<<pos.y<<")\n";
std::this_thread::sleep_for(DELAY);
}
}