listings-Chap23-README-onepage.md
Listings of Chap23.docx
This is the list of listings on one page. You can also view a linked summary.
Listing 23.1: The call to a function template works so long as the function body is valid with the template parameters.
Book listing lst-0010-book.cpp:
// https://godbolt.org/z/aMPj3K7EE
#include <iostream>
struct Number {
int value_;
};
template<typename TYPE>
void print(TYPE value) {
std::cout << value << "\n";
}
int main() {
print(5);
print(-10.25);
print("Flamingo");
Number seven { 7 };
print(seven); // (ERR) cout << seven does not exist
}
Godbolt Listing lst-0010-godb.cpp, https://godbolt.org/z/aMPj3K7EE:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/aMPj3K7EE
#include <iostream>
struct Number {
int value_;
};
template<typename TYPE>
void print(TYPE value) {
std::cout << value << "\n";
}
int main() {
print(5);
print(-10.25);
print("Flamingo");
Number seven { 7 };
print(seven); // (ERR) cout << seven does not exist
}
Listing 23.2: With and without explicit type specification during the call.
Book listing lst-0013-book.cpp:
// https://godbolt.org/z/816Ys17aT
#include <iostream>
using std::cout;
template<typename TYPE>
void func(TYP a) { cout << a <<" TYP\n"; }
void func(int a) { cout << a << " int\n"; }
int main() {
func<int>(8); // Output: 8 TYP
func(8); // Output: 8 int
}
Godbolt Listing lst-0013-godb.cpp, https://godbolt.org/z/816Ys17aT:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/816Ys17aT
#include <iostream>
using std::cout;
template<typename TYPE>
void func(TYP a) { cout << a <<" TYP\n"; }
void func(int a) { cout << a << " int\n"; }
int main() {
func<int>(8); // Output: 8 TYP
func(8); // Output: 8 int
}
Listing 23.3: A template parameter can also be a constant number.
Book listing lst-0015-book.cpp:
// https://godbolt.org/z/c9xzM7EhP
#include <array>
#include <iostream> // cout
using std::array; using std::cout;
template<size_t SIZE>
array<int,SIZE> createArray() {
array<int,SIZE> result{};
return result;
}
int main() {
auto data = createArray<5>();
data[3] = 33;
for(auto e : data) cout << e << " ";
cout << "\n";
}
Godbolt Listing lst-0015-godb.cpp, https://godbolt.org/z/c9xzM7EhP:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/c9xzM7EhP
#include <array>
#include <iostream> // cout
using std::array; using std::cout;
template<size_t SIZE>
array<int,SIZE> createArray() {
array<int,SIZE> result{};
return result;
}
int main() {
auto data = createArray<5>();
data[3] = 33;
for(auto e : data) cout << e << " ";
cout << "\n";
}
Listing 23.4: With auto as a template parameter, you can specify any simple value.
Book listing lst-0017-book.cpp:
template <auto value> void f() { }
f<10>(); // value gets type int
f<'a'>(); // value gets type char
Listing 23.5: With “auto” and …, you can specify any values as template parameters.
Book listing lst-0018-book.cpp:
template<auto ... vs> struct MixedList {};
using Three = MixedList<'a', 100, 'b'>;
Three three{};
Listing 23.6: For “TYPE”, the compiler determines “const&”.
Book listing lst-0020-book.cpp:
// https://godbolt.org/z/fev879zaK
#include <iostream>
const int& a_or_b(int choice) {
static const int a = 42;
static const int b = 73;
if(choice==1)
return a; // return const& to inner variable a
else
return b; // return const& to inner variable b
}
template<typename TYPE>
TYPE add(TYPE a, TYPE b) {
return a + b;
}
int main() {
auto res = add(
a_or_b(0), // const int&
a_or_b(1) ); // const int&
std::cout << res << "\n"; // Output: 115
}
Godbolt Listing lst-0020-godb.cpp, https://godbolt.org/z/fev879zaK:
//#(compile) c++; compiler:g141; options:-O1 -std=c++23; libs:-
// https://godbolt.org/z/fev879zaK
#include <iostream>
const int& a_or_b(int choice) {
static const int a = 42;
static const int b = 73;
if(choice==1)
return a; // return const& to inner variable a
else
return b; // return const& to inner variable b
}
template<typename TYPE>
TYPE add(TYPE a, TYPE b) {
return a + b;
}
int main() {
auto res = add(
a_or_b(0), // const int&
a_or_b(1) ); // const int&
std::cout << res << "\n"; // Output: 115
}
Listing 23.7: A method can also be a template.
Book listing lst-0022-book.cpp:
// https://godbolt.org/z/bfofn76Ke
#include <iostream>
class Printer {
std::ostream& trg_;
public:
explicit Printer(std::ostream& target)
: trg_(target)
{}
template<typename TYPE>
Printer& print(const TYP& arg) {
trg_ << arg;
return *this;
}
};
int main() {
Printer normal(std::cout);
normal.print(7).print(" ").print(3.1415).print("\n");
Printer error(std::cerr);
error.print(8).print(" ").print(2.7183).print("\n");
}
Godbolt Listing lst-0022-godb.cpp, https://godbolt.org/z/bfofn76Ke:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/bfofn76Ke
#include <iostream>
class Printer {
std::ostream& trg_;
public:
explicit Printer(std::ostream& target)
: trg_(target)
{}
template<typename TYPE>
Printer& print(const TYP& arg) {
trg_ << arg;
return *this;
}
};
int main() {
Printer normal(std::cout);
normal.print(7).print(" ").print(3.1415).print("\n");
Printer error(std::cerr);
error.print(8).print(" ").print(2.7183).print("\n");
}
Listing 23.8: You will also find various function templates in the standard library.
Book listing lst-0023-book.cpp:
// https://godbolt.org/z/oTn1K4sGG
#include <vector>
#include <iostream> // cout, ostream
#include <algorithm> // sort, copy
#include <iterator> // ostream_iterator
int main() {
std::ostream_iterator<int> oit(std::cout," ");
std::vector data { 100, 50, 1, 75, 25, 0 }; // vector<int>
std::sort(std::begin(data), std::end(data)); // Iterator pair
std::copy(std::begin(data), std::end(data), oit); // Iterator pair
std::cout << '\n'; // Output: 0 1 25 50 75 100
std::ranges::reverse(data); // Range
std::ranges::copy(data, oit); // Range
std::cout << '\n'; // Output: 100 75 50 25 1 0
}
Godbolt Listing lst-0023-godb.cpp, https://godbolt.org/z/oTn1K4sGG:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/oTn1K4sGG
#include <vector>
#include <iostream> // cout, ostream
#include <algorithm> // sort, copy
#include <iterator> // ostream_iterator
int main() {
std::ostream_iterator<int> oit(std::cout," ");
std::vector data { 100, 50, 1, 75, 25, 0 }; // vector<int>
std::sort(std::begin(data), std::end(data)); // Iterator pair
std::copy(std::begin(data), std::end(data), oit); // Iterator pair
std::cout << '\n'; // Output: 0 1 25 50 75 100
std::ranges::reverse(data); // Range
std::ranges::copy(data, oit); // Range
std::cout << '\n'; // Output: 100 75 50 25 1 0
}
Listing 23.9: Pass your own algorithm ranges as arguments, not the container.
Book listing lst-0024-book.cpp:
// https://godbolt.org/z/h3baE65od
#include <iostream>
#include <vector>
#include <set>
#include <bitset>
#include <ranges>
namespace rng = std::ranges;
std::ostream& printBinary(std::ostream& os, rng::input_range auto&& range) {
for(auto&& elem : range) {
std::bitset<4> x(elem); // Copy number into bitset
os << x << " ";
}
return os;
}
int main()
{
std::vector vdata { 2, 0, 15, 12 };
printBinary(std::cout, vdata) << "\n";
// Output: 0010 0000 1111 1100
std::set sdata { 2, 0, 12, 15 };
printBinary(std::cout, sdata) << "\n";
// Output: 0000 0010 1100 1111
int adata[] = { 0,1,2,13,14,15 };
printBinary(std::cout, adata) << "\n";
// Output: 0000 0001 0010 1101 1110 1111
}
Godbolt Listing lst-0024-godb.cpp, https://godbolt.org/z/h3baE65od:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/h3baE65od
#include <iostream>
#include <vector>
#include <set>
#include <bitset>
#include <ranges>
namespace rng = std::ranges;
std::ostream& printBinary(std::ostream& os, rng::input_range auto&& range) {
for(auto&& elem : range) {
std::bitset<4> x(elem); // Copy number into bitset
os << x << " ";
}
return os;
}
int main()
{
std::vector vdata { 2, 0, 15, 12 };
printBinary(std::cout, vdata) << "\n";
// Output: 0010 0000 1111 1100
std::set sdata { 2, 0, 12, 15 };
printBinary(std::cout, sdata) << "\n";
// Output: 0000 0010 1100 1111
int adata[] = { 0,1,2,13,14,15 };
printBinary(std::cout, adata) << "\n";
// Output: 0000 0001 0010 1101 1110 1111
}
Listing 23.10: Pass your own algorithm iterators as arguments, not the container.
Book listing lst-0025-book.cpp:
// https://godbolt.org/z/13eMxKTfj
#include <iostream>
#include <vector>
#include <set>
#include <bitset>
template<typename IT>
std::ostream& printBinary(std::ostream& os, IT begin, IT end)
{
for(IT it=begin; it != end; ++it) {
std::bitset<4> x(*it); // Copy number into bitset
os << x << " ";
}
return os;
}
int main()
{
std::vector<int> vdata { 2, 0, 15, 12 };
printBinary(std::cout, vdata.cbegin(), vdata.cend()) << "\n";
// Output: 0010 0000 1111 1100
std::set<int> sdata { 2, 0, 12, 15 };
printBinary(std::cout, std::begin(sdata), std::end(sdata)) << "\n";
// Output: 0000 0010 1100 1111
int adata[] = { 0,1,2,13,14,15 };
printBinary(std::cout, std::begin(adata), std::end(adata)) << "\n";
// Output: 0000 0001 0010 1101 1110 1111
}
Godbolt Listing lst-0025-godb.cpp, https://godbolt.org/z/13eMxKTfj:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/13eMxKTfj
#include <iostream>
#include <vector>
#include <set>
#include <bitset>
template<typename IT>
std::ostream& printBinary(std::ostream& os, IT begin, IT end)
{
for(IT it=begin; it != end; ++it) {
std::bitset<4> x(*it); // Copy number into bitset
os << x << " ";
}
return os;
}
int main()
{
std::vector<int> vdata { 2, 0, 15, 12 };
printBinary(std::cout, vdata.cbegin(), vdata.cend()) << "\n";
// Output: 0010 0000 1111 1100
std::set<int> sdata { 2, 0, 12, 15 };
printBinary(std::cout, std::begin(sdata), std::end(sdata)) << "\n";
// Output: 0000 0010 1100 1111
int adata[] = { 0,1,2,13,14,15 };
printBinary(std::cout, std::begin(adata), std::end(adata)) << "\n";
// Output: 0000 0001 0010 1101 1110 1111
}
Listing 23.11: How to find the range of integer types.
Book listing lst-0027-book.cpp:
// https://godbolt.org/z/r83Yeon7r
#include <iostream> // cout
#include <limits> // numeric_limits
template<typename INT_TYP> // Template with type argument
void infos(const char* name) {
using L = typename std::numeric_limits<INT_TYP>; // rename for brevity
std::cout
<< name
<< " number of bits:" << L::digits // Bits without sign bit
<< " sign:" << L::is_signed // stores sign?
<< " min:"<< (long long)L::min() // smallest possible value
<< " max:"<< (long long)L::max() // largest possible value
<< "\n";
}
int main() {
infos<signed char>("char"); // smallest int type
infos<short>("short");
infos<int>("int");
infos<long>("long");
infos<long long>("long long"); // largest int type
}
Godbolt Listing lst-0027-godb.cpp, https://godbolt.org/z/r83Yeon7r:
//#(compile) c++; compiler:g141; options:-O1 -std=c++23; libs:-
// https://godbolt.org/z/r83Yeon7r
#include <iostream> // cout
#include <limits> // numeric_limits
template<typename INT_TYP> // Template with type argument
void infos(const char* name) {
using L = typename std::numeric_limits<INT_TYP>; // rename for brevity
std::cout
<< name
<< " number of bits:" << L::digits // Bits without sign bit
<< " sign:" << L::is_signed // stores sign?
<< " min:"<< (long long)L::min() // smallest possible value
<< " max:"<< (long long)L::max() // largest possible value
<< "\n";
}
int main() {
infos<signed char>("char"); // smallest int type
infos<short>("short");
infos<int>("int");
infos<long>("long");
infos<long long>("long long"); // largest int type
}
Listing 23.12: A function as a parameter.
Book listing lst-0028-book.cpp:
#include <functional> // function
int calculate(int a, int b, std::function<int(int,int)> binop) {
return binop(a,b);
}
Listing 23.13: Use the name of a suitable function as a function parameter.
Book listing lst-0031-book.cpp:
// https://godbolt.org/z/q719j41er
#include <functional> // function
#include <iostream> // cout
int calculate(int a, int b, std::function<int(int,int)> binop) {
return binop(a,b);
}
int plus(int a, int b) { return a+b; }
int times(int a, int b) { return a*b; }
int main() {
std::cout << calculate(3, 4, plus) << "\n"; // Output: 7
std::cout << calculate(3, 4, times) << "\n"; // Output: 12
}
Godbolt Listing lst-0031-godb.cpp, https://godbolt.org/z/q719j41er:
//#(compile) c++; compiler:g141; options:-O1 -std=c++23; libs:-
// https://godbolt.org/z/q719j41er
#include <functional> // function
#include <iostream> // cout
int calculate(int a, int b, std::function<int(int,int)> binop) {
return binop(a,b);
}
int plus(int a, int b) { return a+b; }
int times(int a, int b) { return a*b; }
int main() {
std::cout << calculate(3, 4, plus) << "\n"; // Output: 7
std::cout << calculate(3, 4, times) << "\n"; // Output: 12
}
Listing 23.14: It doesn’t matter whether you use the address operator when calling or not.
Book listing lst-0034-book.cpp:
// https://godbolt.org/z/c9Eh346cq
#include <functional> // function
#include <iostream> // cout
int calculate(int a, int b, std::function<int(int,int)> binop) {
return binop(a,b);
}
int plus(int a, int b) { return a+b; }
int times(int a, int b) { return a*b; }
int main() {
std::cout << calculate(3, 4, plus) << "\n"; // Value notation
std::cout << calculate(3, 4, times) << "\n"; // Value notation
std::cout << calculate(3, 4, &plus) << "\n"; // Pointer notation
std::cout << calculate(3, 4, ×) << "\n"; // Pointer notation
}
Godbolt Listing lst-0034-godb.cpp, https://godbolt.org/z/c9Eh346cq:
//#(compile) c++; compiler:g141; options:-O1 -std=c++23; libs:-
// https://godbolt.org/z/c9Eh346cq
#include <functional> // function
#include <iostream> // cout
int calculate(int a, int b, std::function<int(int,int)> binop) {
return binop(a,b);
}
int plus(int a, int b) { return a+b; }
int times(int a, int b) { return a*b; }
int main() {
std::cout << calculate(3, 4, plus) << "\n"; // Value notation
std::cout << calculate(3, 4, times) << "\n"; // Value notation
std::cout << calculate(3, 4, &plus) << "\n"; // Pointer notation
std::cout << calculate(3, 4, ×) << "\n"; // Pointer notation
}
Listing 23.15: A class with “operator()” creates function objects.
Book listing lst-0035-book.cpp:
// https://godbolt.org/z/xvfvG8hrd
#include <iostream> // cout
using std::cout;
class Increment {
int amount_;
public:
explicit Increment(int amount) : amount_{amount} {}
int operator()(int value) const { // makes instances callable
return value + amount_;
}
void clear() {
amount_ = 0;
}
};
int main() {
Increment plusFour{4}; // create instance
Increment plusEleven{11}; // another instance
cout << plusFour(8) << "\n"; // Output: 12
int result = 2 * plusEleven(5) - 7; // result is 25
cout << plusEleven(result/5) << "\n"; // Output: 16
cout << 3 * Increment{1}(7) << "\n"; // Output: 24
Increment plusZero = plusEleven;
plusZero.clear(); // change state
cout << plusZero(1) << "\n"; // Output: 1
}
Godbolt Listing lst-0035-godb.cpp, https://godbolt.org/z/xvfvG8hrd:
//#(compile) c++; compiler:g141; options:-O1 -std=c++23; libs:-
// https://godbolt.org/z/xvfvG8hrd
#include <iostream> // cout
using std::cout;
class Increment {
int amount_;
public:
explicit Increment(int amount) : amount_{amount} {}
int operator()(int value) const { // makes instances callable
return value + amount_;
}
void clear() {
amount_ = 0;
}
};
int main() {
Increment plusFour{4}; // create instance
Increment plusEleven{11}; // another instance
cout << plusFour(8) << "\n"; // Output: 12
int result = 2 * plusEleven(5) - 7; // result is 25
cout << plusEleven(result/5) << "\n"; // Output: 16
cout << 3 * Increment{1}(7) << "\n"; // Output: 24
Increment plusZero = plusEleven;
plusZero.clear(); // change state
cout << plusZero(1) << "\n"; // Output: 1
}
Listing 23.16: A class with a normal method.
Book listing lst-0038-book.cpp:
// https://godbolt.org/z/MfKzd8bxa
#include <iostream> // cout
using std::cout;
class Add {
int amount_;
public:
explicit Add(int amount) : amount_{amount} {}
int add(int value) const { // instead of operator()
return value + amount_;
}
void clear() {
amount_ = 0;
}
};
int main() {
Add plusFour{4}; // create instance
Add plusEleven{11}; // another instance
cout << plusFour.add(8) << "\n"; // Output: 12
int result = 2 * plusEleven.add(5) - 7; // result is 25
cout << plusEleven.add(result/5) << "\n"; // Output: 16
cout << 3 * Add{1}.add(7) << "\n"; // Output: 24
Add plusZilch = plusEleven;
plusZilch.clear(); // change state
cout << plusZilch.add(1) << "\n"; // Output: 1
}
Godbolt Listing lst-0038-godb.cpp, https://godbolt.org/z/MfKzd8bxa:
//#(compile) c++; compiler:g141; options:-O1 -std=c++23; libs:-
// https://godbolt.org/z/MfKzd8bxa
#include <iostream> // cout
using std::cout;
class Add {
int amount_;
public:
explicit Add(int amount) : amount_{amount} {}
int add(int value) const { // instead of operator()
return value + amount_;
}
void clear() {
amount_ = 0;
}
};
int main() {
Add plusFour{4}; // create instance
Add plusEleven{11}; // another instance
cout << plusFour.add(8) << "\n"; // Output: 12
int result = 2 * plusEleven.add(5) - 7; // result is 25
cout << plusEleven.add(result/5) << "\n"; // Output: 16
cout << 3 * Add{1}.add(7) << "\n"; // Output: 24
Add plusZilch = plusEleven;
plusZilch.clear(); // change state
cout << plusZilch.add(1) << "\n"; // Output: 1
}
Listing 23.17: With “operator<” as a function, you can only implement one sort order.
Book listing lst-0039-book.cpp:
// https://godbolt.org/z/3ch51ov87
#include <set>
#include <string>
#include <iostream> // cout
using std::string; using std::set; using std::cout;
struct Dwarf {
string name_;
unsigned year_;
};
bool operator<(const Dwarf& a, const Dwarf& b) {
return a.name_ < b.name_;
}
int main() {
set dwarves{ Dwarf{"Balin", 2763}, Dwarf{"Dwalin", 2772},
Dwarf{"Oin", 2774}, Dwarf{"Gloin", 2783}, Dwarf{"Thorin", 2746},
Dwarf{"Fili", 2859}, Dwarf{"Kili", 2864} };
for(const auto& z : dwarves) // sorted output: "Balin" to "Thorin"
cout << z.name_ << " ";
cout << "\n";
}
Godbolt Listing lst-0039-godb.cpp, https://godbolt.org/z/3ch51ov87:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/3ch51ov87
#include <set>
#include <string>
#include <iostream> // cout
using std::string; using std::set; using std::cout;
struct Dwarf {
string name_;
unsigned year_;
};
bool operator<(const Dwarf& a, const Dwarf& b) {
return a.name_ < b.name_;
}
int main() {
set dwarves{ Dwarf{"Balin", 2763}, Dwarf{"Dwalin", 2772},
Dwarf{"Oin", 2774}, Dwarf{"Gloin", 2783}, Dwarf{"Thorin", 2746},
Dwarf{"Fili", 2859}, Dwarf{"Kili", 2864} };
for(const auto& z : dwarves) // sorted output: "Balin" to "Thorin"
cout << z.name_ << " ";
cout << "\n";
}
Listing 23.18: A no-frills functor with great utility.
Book listing lst-0041-book.cpp:
struct ByYear { // implements less-than by Dwarf::year_
bool operator()(const Dwarf& a, const Dwarf& b) const {
return a.year_ < b.year_;
}
};
GodboltId:PebG9bn9K
Book listing lst-0042-book.cpp:
// https://godbolt.org/z/PebG9bn9K
set<Dwarf,ByYear> dwarves2{begin(dwarves), end(dwarves)};
for(const auto& z : dwarves2) // differently sorted output
cout << z.year_ << " ";
Godbolt Listing lst-0042-godb.cpp, https://godbolt.org/z/PebG9bn9K:
//#(compile) c++; compiler:g141; options:-O1 -std=c++23; libs:-
// https://godbolt.org/z/PebG9bn9K
set<Dwarf,ByYear> dwarves2{begin(dwarves), end(dwarves)};
for(const auto& z : dwarves2) // differently sorted output
cout << z.year_ << " ";
Listing 23.19: Many algorithms in the standard library also work with “operator<”.
Book listing lst-0046-book.cpp:
// https://godbolt.org/z/YKzsW49G8
#include <vector>
#include <algorithm> // sort
// Definitions and further includes as before
int main() {
vector dwarves{ // initialize as before
/* sort */
std::sort(begin(dwarves), end(dwarves));
// output as before …
Godbolt Listing lst-0046-godb.cpp, https://godbolt.org/z/YKzsW49G8:
//#(compile) c++; compiler:g141; options:-O1 -std=c++23; libs:-
// https://godbolt.org/z/YKzsW49G8
#include <vector>
#include <algorithm> // sort
// Definitions and further includes as before
int main() {
vector dwarves{ // initialize as before
/* sort */
std::sort(begin(dwarves), end(dwarves));
// output as before …
Listing 23.20: With the capture clause, you can access external variables in the lambda.
Book listing lst-0053-book.cpp:
// https://godbolt.org/z/eh6jnjK9z
#include <vector>
#include <string>
#include <algorithm> // sort
#include <iostream> // cout
using std::string; using std::vector; using std::cout;
// as before
int main() {
vector dwarves{ // as before
/* sort */
bool backwards = true; // or false. Variable outside the lambda
std::ranges::sort(dwarves,
[backwards](const Dwarf& a, const Dwarf& b) {
if(backwards)
return a.name_ > b.name_;
else
return a.name_ < b.name_;
}
);
/* output */
for(const auto& z : dwarves) // backwards: "Thorin" to "Balin"
cout << z.name_ << " ";
cout << "\n";
}
Godbolt Listing lst-0053-godb.cpp, https://godbolt.org/z/eh6jnjK9z:
//#(compile) c++; compiler:g141; options:-O1 -std=c++23; libs:-
// https://godbolt.org/z/eh6jnjK9z
#include <vector>
#include <string>
#include <algorithm> // sort
#include <iostream> // cout
using std::string; using std::vector; using std::cout;
// as before
int main() {
vector dwarves{ // as before
/* sort */
bool backwards = true; // or false. Variable outside the lambda
std::ranges::sort(dwarves,
[backwards](const Dwarf& a, const Dwarf& b) {
if(backwards)
return a.name_ > b.name_;
else
return a.name_ < b.name_;
}
);
/* output */
for(const auto& z : dwarves) // backwards: "Thorin" to "Balin"
cout << z.name_ << " ";
cout << "\n";
}
Listing 23.21: The capture clause can also contain references.
Book listing lst-0054-book.cpp:
// https://godbolt.org/z/j7qoMdG3n
#include <vector>
#include <string>
#include <algorithm> // sort
#include <iostream> // cout
using std::string; using std::vector; using std::cout;
// as before
int main() {
vector dwarfs{ // as before
/* sort */
bool backwards = true; // or false. Variable outside the lambda
unsigned rightway = 0; // counts <
unsigned wrongway = 0; // counts >
std::ranges::sort(dwarves,
[backwards,&rightway,&wrongway](const Dwarf& a, const Dwarf& b) {
bool result = backwards
? a.name_ > b.name_
: a.name_ < b.name_;
if(result==false) ++wrongway; else ++rightway;
return result;
}
);
/* output */
cout << "Wrongway:" << wrongway << " Rightway: " << rightway << "\n";
for(const auto& z : dwarves) // backwards: "Thorin" to "Balin"
cout << z.name_ << " ";
cout << "\n";
}
Godbolt Listing lst-0054-godb.cpp, https://godbolt.org/z/j7qoMdG3n:
//#(compile) c++; compiler:g141; options:-O1 -std=c++23; libs:-
// https://godbolt.org/z/j7qoMdG3n
#include <vector>
#include <string>
#include <algorithm> // sort
#include <iostream> // cout
using std::string; using std::vector; using std::cout;
// as before
int main() {
vector dwarfs{ // as before
/* sort */
bool backwards = true; // or false. Variable outside the lambda
unsigned rightway = 0; // counts <
unsigned wrongway = 0; // counts >
std::ranges::sort(dwarves,
[backwards,&rightway,&wrongway](const Dwarf& a, const Dwarf& b) {
bool result = backwards
? a.name_ > b.name_
: a.name_ < b.name_;
if(result==false) ++wrongway; else ++rightway;
return result;
}
);
/* output */
cout << "Wrongway:" << wrongway << " Rightway: " << rightway << "\n";
for(const auto& z : dwarves) // backwards: "Thorin" to "Balin"
cout << z.name_ << " ";
cout << "\n";
}
Listing 23.22: “mutable” makes value captures in lambdas mutable.
Book listing lst-0056-book.cpp:
// https://godbolt.org/z/zMWo69974
#include <iostream>
int main() {
int count = 0;
auto plus1 = [count](int x) mutable { // count as a copy
std::cout << ++count; return x+1;
};
for(int i=0; i<5; ++i) {
plus1(i);
}
std::cout << "\n";
// Output: 12345
}
Godbolt Listing lst-0056-godb.cpp, https://godbolt.org/z/zMWo69974:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/zMWo69974
#include <iostream>
int main() {
int count = 0;
auto plus1 = [count](int x) mutable { // count as a copy
std::cout << ++count; return x+1;
};
for(int i=0; i<5; ++i) {
plus1(i);
}
std::cout << "\n";
// Output: 12345
}
Listing 23.23: If possible, better without mutable.
Book listing lst-0057-book.cpp:
// https://godbolt.org/z/8GxPMEc5o
#include <iostream>
int main() {
int count = 0;
auto plus1 = [&count](int x) { // count as reference
++count; return x+1;
};
for(int i=0; i<5; ++i) { plus1(i); }
std::cout << "plus1 was called " << count << " times\n";
// Output: plus1 was called 5 times
}
Godbolt Listing lst-0057-godb.cpp, https://godbolt.org/z/8GxPMEc5o:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/8GxPMEc5o
#include <iostream>
int main() {
int count = 0;
auto plus1 = [&count](int x) { // count as reference
++count; return x+1;
};
for(int i=0; i<5; ++i) { plus1(i); }
std::cout << "plus1 was called " << count << " times\n";
// Output: plus1 was called 5 times
}
GodboltId:xnbvEx5Kc
Book listing lst-0060-book.cpp:
// https://godbolt.org/z/xnbvEx5Kc
#include <iostream>
#include <string>
using std::cout; using std::string; using namespace std::literals;
auto min2 = [](const auto &a, const auto &b) {
return a<b ? a : b;
};
auto min3 = [](const auto &a, const auto &b, const auto &c) {
return min2(a, min2(b,c));
};
int main() {
cout << min3( 3, 7, 2 ) << '\n'; // Output: 2
cout << min3( 8.11, 113.2, -3.1 ) << '\n'; // Output: –3.1
cout << min3( "Zoo"s, "Ape"s, "Mule"s ) << '\n'; // Output: Ape
}
Godbolt Listing lst-0060-godb.cpp, https://godbolt.org/z/xnbvEx5Kc:
//#(compile) c++; compiler:g141; options:-O1 -std=c++23; libs:-
// https://godbolt.org/z/xnbvEx5Kc
#include <iostream>
#include <string>
using std::cout; using std::string; using namespace std::literals;
auto min2 = [](const auto &a, const auto &b) {
return a<b ? a : b;
};
auto min3 = [](const auto &a, const auto &b, const auto &c) {
return min2(a, min2(b,c));
};
int main() {
cout << min3( 3, 7, 2 ) << '\n'; // Output: 2
cout << min3( 8.11, 113.2, -3.1 ) << '\n'; // Output: –3.1
cout << min3( "Zoo"s, "Ape"s, "Mule"s ) << '\n'; // Output: Ape
}
GodboltId:nenW8aM81
Book listing lst-0061-book.cpp:
// https://godbolt.org/z/nenW8aM81
auto min2 = []<typename T>(const T &a, const T &b) {
return a<b ? a : b;
};
auto min3 = []<typename T>(const T &a, const T &b, const T &c) {
return min2(a, min2(b,c));
};
Godbolt Listing lst-0061-godb.cpp, https://godbolt.org/z/nenW8aM81:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/nenW8aM81
auto min2 = []<typename T>(const T &a, const T &b) {
return a<b ? a : b;
};
auto min3 = []<typename T>(const T &a, const T &b, const T &c) {
return min2(a, min2(b,c));
};
Listing 23.24: Concepts can be written in different ways.
Book listing lst-0062-book.cpp:
// https://godbolt.org/z/jP75nY4EW
#include <concepts> // integral
#include <iostream>
using namespace std;
// Concept explicitly with requires
template<typename T> requires integral<T>
auto add_1(T val) { return val+1; }
// abbreviated concept
template<integral T>
auto add_2(T val) { return val+2; }
// abbreviated function template with concept
auto add_3(integral auto val) { return val+3; }
// Ad-hoc requirements for function template
auto add_4(auto val) requires integral<decltype(val)>
{ return val+4; }
int main() {
cout << add_1(1) << '\n'; // Output: 2
cout << add_2(1) << '\n'; // Output: 3
cout << add_3(1) << '\n'; // Output: 4
cout << add_4(1) << '\n'; // Output: 5
cout << add_3("text") << '\n'; // (ERR) Error
integral auto val = add_1(99); // also for auto variables
cout << val << '\n'; // Output: 100
}
Godbolt Listing lst-0062-godb.cpp, https://godbolt.org/z/jP75nY4EW:
//#(compile) c++; compiler:g141; options:-O1 -std=c++23; libs:-
// https://godbolt.org/z/jP75nY4EW
#include <concepts> // integral
#include <iostream>
using namespace std;
// Concept explicitly with requires
template<typename T> requires integral<T>
auto add_1(T val) { return val+1; }
// abbreviated concept
template<integral T>
auto add_2(T val) { return val+2; }
// abbreviated function template with concept
auto add_3(integral auto val) { return val+3; }
// Ad-hoc requirements for function template
auto add_4(auto val) requires integral<decltype(val)>
{ return val+4; }
int main() {
cout << add_1(1) << '\n'; // Output: 2
cout << add_2(1) << '\n'; // Output: 3
cout << add_3(1) << '\n'; // Output: 4
cout << add_4(1) << '\n'; // Output: 5
cout << add_3("text") << '\n'; // (ERR) Error
integral auto val = add_1(99); // also for auto variables
cout << val << '\n'; // Output: 100
}
Listing 23.25: With concepts, you can restrict individual overloads.
Book listing lst-0063-book.cpp:
// https://godbolt.org/z/Kxrz5ETh6
#include <concepts> // integral, floating_point
#include <iostream>
using namespace std;
int64_t trunc_to_10(integral auto val) { return (val/10)*10; }
int64_t trunc_to_10(floating_point auto val) { return int64_t(val/10)*10; }
int main() {
cout << trunc_to_10(144) << '\n'; // Output: 140
cout << trunc_to_10(122.2) << '\n'; // Output: 120
}
Godbolt Listing lst-0063-godb.cpp, https://godbolt.org/z/Kxrz5ETh6:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/Kxrz5ETh6
#include <concepts> // integral, floating_point
#include <iostream>
using namespace std;
int64_t trunc_to_10(integral auto val) { return (val/10)*10; }
int64_t trunc_to_10(floating_point auto val) { return int64_t(val/10)*10; }
int main() {
cout << trunc_to_10(144) << '\n'; // Output: 140
cout << trunc_to_10(122.2) << '\n'; // Output: 120
}
GodboltId:eaGre4bqr
Book listing lst-0065-book.cpp:
// https://godbolt.org/z/eaGre4bqr
auto min2(const std::integral auto &a, const std::integral auto &b) {
return a<b ? a : b;
};
auto min3 = []<std::integral T>(const T &a, const T &b, const T &c) {
return min2(a, min2(b,c));
};
int main() {
cout << min3( 3, 7, 2 ) << '\n';
cout << min3( 8.11, 113.2, -3.1 ) << '\n'; // (ERR) Error: not an integral type
}
Godbolt Listing lst-0065-godb.cpp, https://godbolt.org/z/eaGre4bqr:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/eaGre4bqr
auto min2(const std::integral auto &a, const std::integral auto &b) {
return a<b ? a : b;
};
auto min3 = []<std::integral T>(const T &a, const T &b, const T &c) {
return min2(a, min2(b,c));
};
int main() {
cout << min3( 3, 7, 2 ) << '\n';
cout << min3( 8.11, 113.2, -3.1 ) << '\n'; // (ERR) Error: not an integral type
}
Listing 23.26: Specify additional conditions with requires.
Book listing lst-0066-book.cpp:
// https://godbolt.org/z/fxoo4h9Gj
#include <concepts>
#include <iostream>
#include <string>
using namespace std; using namespace std::literals;
string mk_string(integral auto val) { return to_string(val); }
string mk_string(string val) { return '['+val+']'; }
template<typename T>
requires copyable<T> && // Type requirement
requires (T t) { mk_string(t) + mk_string(t); } && // simple requirement
requires (T t) { // composite requirement
{mk_string(t)} -> same_as<string>; // valid expression must meet condition
}
string dbl_quote(const T& val) {
T val2{val}; // Create a copy (for demonstration purposes only)
return '"' + mk_string(val) + mk_string(val2) + '"';
}
int main() {
cout << dbl_quote(10) << '\n'; // Output: "1010"
cout << dbl_quote("ab"s) << '\n'; // Output: "[ab][ab]"
cout << dbl_quote(3.14) << '\n'; // (ERR) Error: no suitable mk_string overload
}
Godbolt Listing lst-0066-godb.cpp, https://godbolt.org/z/fxoo4h9Gj:
//#(compile) c++; compiler:g141; options:-O1 -std=c++23; libs:-
// https://godbolt.org/z/fxoo4h9Gj
#include <concepts>
#include <iostream>
#include <string>
using namespace std; using namespace std::literals;
string mk_string(integral auto val) { return to_string(val); }
string mk_string(string val) { return '['+val+']'; }
template<typename T>
requires copyable<T> && // Type requirement
requires (T t) { mk_string(t) + mk_string(t); } && // simple requirement
requires (T t) { // composite requirement
{mk_string(t)} -> same_as<string>; // valid expression must meet condition
}
string dbl_quote(const T& val) {
T val2{val}; // Create a copy (for demonstration purposes only)
return '"' + mk_string(val) + mk_string(val2) + '"';
}
int main() {
cout << dbl_quote(10) << '\n'; // Output: "1010"
cout << dbl_quote("ab"s) << '\n'; // Output: "[ab][ab]"
cout << dbl_quote(3.14) << '\n'; // (ERR) Error: no suitable mk_string overload
}
Listing 23.27: Define recurring requirements with concept.
Book listing lst-0067-book.cpp:
// https://godbolt.org/z/Tcxnr6jTM
template<typename T>
concept dbl_quotable = copyable<T> &&
requires(T t) { mk_string(t) + mk_string(t); } &&
requires(T t) {
{mk_string(t)} -> same_as<string>;
};
string dbl_quote(const dbl_quotable auto& val) {
auto val2{val}; // Create a copy (for demonstration purposes only)
return '"' + mk_string(val) + mk_string(val2) + '"';
}
Godbolt Listing lst-0067-godb.cpp, https://godbolt.org/z/Tcxnr6jTM:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/Tcxnr6jTM
template<typename T>
concept dbl_quotable = copyable<T> &&
requires(T t) { mk_string(t) + mk_string(t); } &&
requires(T t) {
{mk_string(t)} -> same_as<string>;
};
string dbl_quote(const dbl_quotable auto& val) {
auto val2{val}; // Create a copy (for demonstration purposes only)
return '"' + mk_string(val) + mk_string(val2) + '"';
}
GodboltId:9qsGW6M8Y
Book listing lst-0068-book.cpp:
// https://godbolt.org/z/9qsGW6M8Y
template<std::ranges::range T> // a range over type T
using ValueTypeOfRange = std::ranges::range_value_t<T>;
// or
template<typename T>
requires std::ranges::range<T> // a range over type T
using ValueTypeOfRange = std::ranges::range_value_t<T>;
// results in:
ValueTypeOfRange<std::vector<int>> x; // x is int
ValueTypeOfRange<std::string> y; // y is char
ValueTypeOfRange<std::list<double>> z; // z is double
ValueTypeOfRange<int> w; // (ERR) int is not a range
Godbolt Listing lst-0068-godb.cpp, https://godbolt.org/z/9qsGW6M8Y:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/9qsGW6M8Y
template<std::ranges::range T> // a range over type T
using ValueTypeOfRange = std::ranges::range_value_t<T>;
// or
template<typename T>
requires std::ranges::range<T> // a range over type T
using ValueTypeOfRange = std::ranges::range_value_t<T>;
// results in:
ValueTypeOfRange<std::vector<int>> x; // x is int
ValueTypeOfRange<std::string> y; // y is char
ValueTypeOfRange<std::list<double>> z; // z is double
ValueTypeOfRange<int> w; // (ERR) int is not a range
Listing 23.28: This is how you use concepts in a constexpr if.
Book listing lst-0069-book.cpp:
if constexpr std::integral<T> {
// T is an integral type
} else if constexpr std::floating_point<T> {
// T is a floating-point type
} else {
// T is neither
}
Listing 23.29: A class template takes a type as a formal parameter.
Book listing lst-0073-book.cpp:
// https://godbolt.org/z/jqzTMxYKv
template <std::copyable T> // C++20 concept
class MyContainer {
T data_;
public:
void setData(const T& d) { data_ = d; }
T getData() const { return data_; }
};
Godbolt Listing lst-0073-godb.cpp, https://godbolt.org/z/jqzTMxYKv:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/jqzTMxYKv
template <std::copyable T> // C++20 concept
class MyContainer {
T data_;
public:
void setData(const T& d) { data_ = d; }
T getData() const { return data_; }
};
Listing 23.30: Method definitions outside the body of a class template are syntactically somewhat more complex.
Book listing lst-0075-book.cpp:
// https://godbolt.org/z/4fK5WdoG8
template <std::copyable T>
class MyContainer {
T data_;
public:
void setData(const T& d);
T getData() const;
};
template <std::copyable T>
void MyContainer<T>::setData(const T& d) {
data_ = d;
}
template <std::copyable T>
T MyContainer<T>::getData() const {
return data_;
}
Godbolt Listing lst-0075-godb.cpp, https://godbolt.org/z/4fK5WdoG8:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/4fK5WdoG8
template <std::copyable T>
class MyContainer {
T data_;
public:
void setData(const T& d);
T getData() const;
};
template <std::copyable T>
void MyContainer<T>::setData(const T& d) {
data_ = d;
}
template <std::copyable T>
T MyContainer<T>::getData() const {
return data_;
}
Listing 23.31: Specializing class template methods like function templates.
Book listing lst-0076-book.cpp:
// https://godbolt.org/z/M6earoWMn
#include <iostream>
#include <string>
#include <concepts> // copyable, C++20
template <std::copyable T>
class MyContainer {
T data_;
public:
void setData(const T& d) { data_ = d; } // general case
T getData() const { return data_; } // general case
};
template<> // Specialization
void MyContainer<std::string>::setData(const std::string& d) {
data_ = "[" + d + "]";
}
int main() {
MyContainer<std::string> mcString;
mcString.setData("History");
std::cout << mcString.getData() << '\n'; // Output: [History]
MyContainer<int> mcInt;
mcInt.setData(5);
std::cout << mcInt.getData() << '\n'; // Output: 5
}
Godbolt Listing lst-0076-godb.cpp, https://godbolt.org/z/M6earoWMn:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/M6earoWMn
#include <iostream>
#include <string>
#include <concepts> // copyable, C++20
template <std::copyable T>
class MyContainer {
T data_;
public:
void setData(const T& d) { data_ = d; } // general case
T getData() const { return data_; } // general case
};
template<> // Specialization
void MyContainer<std::string>::setData(const std::string& d) {
data_ = "[" + d + "]";
}
int main() {
MyContainer<std::string> mcString;
mcString.setData("History");
std::cout << mcString.getData() << '\n'; // Output: [History]
MyContainer<int> mcInt;
mcInt.setData(5);
std::cout << mcInt.getData() << '\n'; // Output: 5
}
Listing 23.32: This is how you create instances from a template class.
Book listing lst-0077-book.cpp:
// https://godbolt.org/z/9vP3o68bW
#include <iostream>
#include <string>
#include <concepts> // copyable, C++20
template <std::copyable T>
class MyContainer {
T data_;
public:
void setData(const T& d) { data_ = d; }
T getData() const { return data_; }
};
class IntValue {
int val_;
public:
explicit IntValue(int val=0) : val_(val) {}
int getInt() const { return val_; }
};
int main() {
// C-array with three MyContainer<double> instances
MyContainer<double> dcont[3];
dcont[0].setData(123.123);
dcont[1].setData(234.234);
std::cout << dcont[0].getData() << std::endl;
std::cout << dcont[1].getData() << std::endl;
// custom data type as formal parameter
IntValue ival{100'000};
MyContainer<IntValue> scont;
scont.setData(ival);
std::cout << scont.getData().getInt() << std::endl;
// string as formal parameter
std::string str("Text");
MyContainer<std::string> strCont;
strCont.setData(str);
std::cout << strCont.getData() << std::endl;
}
Godbolt Listing lst-0077-godb.cpp, https://godbolt.org/z/9vP3o68bW:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/9vP3o68bW
#include <iostream>
#include <string>
#include <concepts> // copyable, C++20
template <std::copyable T>
class MyContainer {
T data_;
public:
void setData(const T& d) { data_ = d; }
T getData() const { return data_; }
};
class IntValue {
int val_;
public:
explicit IntValue(int val=0) : val_(val) {}
int getInt() const { return val_; }
};
int main() {
// C-array with three MyContainer<double> instances
MyContainer<double> dcont[3];
dcont[0].setData(123.123);
dcont[1].setData(234.234);
std::cout << dcont[0].getData() << std::endl;
std::cout << dcont[1].getData() << std::endl;
// custom data type as formal parameter
IntValue ival{100'000};
MyContainer<IntValue> scont;
scont.setData(ival);
std::cout << scont.getData().getInt() << std::endl;
// string as formal parameter
std::string str("Text");
MyContainer<std::string> strCont;
strCont.setData(str);
std::cout << strCont.getData() << std::endl;
}
Listing 23.33: Deduce template parameters from constructor arguments.
Book listing lst-0078-book.cpp:
// https://godbolt.org/z/YaEW5aTra
#include <string>
#include <vector>
#include <set>
#include <tuple>
#include <memory> // shared_ptr
template <typename T>
class MyStuff {
T data_;
public:
MyStuff() : data_{} {} // default constructor
MyStuff(const T& d) : data_{d} { } // copy constructor
T getStuff() const { return data_; }
};
class IntValue {
int val_;
public:
explicit IntValue(int val=0) : val_(val) {}
int getInt() const { return val_; }
};
int main() {
MyStuff intStuff(12); // becomes MyStuff<int>
std::vector vs{ 1,2,3,4 }; // becomes vector<int>
MyStuff ivalStuff{ IntValue{33} }; // becomes MyStuff<IntValue>
std::tuple tpl{ 23, 'a' }; // becomes tuple<int,char>
std::set twoThree (vs.begin()+1, vs.end()-1); // becomes set<int>
// The compiler cannot deduce:
MyStuff<double> dblStuff; // no constructor argument
std::vector<char> vcs(10); // size 10, but of what type?
std::shared_ptr<int> ptr{new int{88}}; // no rule for int*
}
Godbolt Listing lst-0078-godb.cpp, https://godbolt.org/z/YaEW5aTra:
//#(compile) c++; compiler:g141; options:-O1 -std=c++23; libs:-
// https://godbolt.org/z/YaEW5aTra
#include <string>
#include <vector>
#include <set>
#include <tuple>
#include <memory> // shared_ptr
template <typename T>
class MyStuff {
T data_;
public:
MyStuff() : data_{} {} // default constructor
MyStuff(const T& d) : data_{d} { } // copy constructor
T getStuff() const { return data_; }
};
class IntValue {
int val_;
public:
explicit IntValue(int val=0) : val_(val) {}
int getInt() const { return val_; }
};
int main() {
MyStuff intStuff(12); // becomes MyStuff<int>
std::vector vs{ 1,2,3,4 }; // becomes vector<int>
MyStuff ivalStuff{ IntValue{33} }; // becomes MyStuff<IntValue>
std::tuple tpl{ 23, 'a' }; // becomes tuple<int,char>
std::set twoThree (vs.begin()+1, vs.end()-1); // becomes set<int>
// The compiler cannot deduce:
MyStuff<double> dblStuff; // no constructor argument
std::vector<char> vcs(10); // size 10, but of what type?
std::shared_ptr<int> ptr{new int{88}}; // no rule for int*
}
Listing 23.34: You have been able to use make_ helper functions and auto for a long time.
Book listing lst-0079-book.cpp:
auto tpl = std::make_tuple( 5, 'x' );
auto ptr = std::make_shared( 5 );
GodboltId:dMTnbT1v4
Book listing lst-0080-book.cpp:
// https://godbolt.org/z/dMTnbT1v4
#include <iostream>
#include <concepts> // copyable, C+20
template<std::copyable T, std::copyable U>
class MyPair {
T data01_;
U data02_;
public:
MyPair(const T& t,const U& u) : data01_{t}, data02_{u} {}
void print(std::ostream& os) const {
os << data01_ << " : " << data02_ << std::endl;
}
};
int main() {
std::string month{"January"};
int temp = -5;
MyPair<std::string, int> temperature{month, temp};
temperature.print(std::cout);
}
Godbolt Listing lst-0080-godb.cpp, https://godbolt.org/z/dMTnbT1v4:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/dMTnbT1v4
#include <iostream>
#include <concepts> // copyable, C+20
template<std::copyable T, std::copyable U>
class MyPair {
T data01_;
U data02_;
public:
MyPair(const T& t,const U& u) : data01_{t}, data02_{u} {}
void print(std::ostream& os) const {
os << data01_ << " : " << data02_ << std::endl;
}
};
int main() {
std::string month{"January"};
int temp = -5;
MyPair<std::string, int> temperature{month, temp};
temperature.print(std::cout);
}
GodboltId:jbafeEdoW
Book listing lst-0081-book.cpp:
// https://godbolt.org/z/jbafeEdoW
#include <iostream>
#include <concepts> // copyable, C++20
template<std::copyable T, std::copyable U=T>
class MyPair {
T data01_;
U data02_;
public:
MyPair(const T& t,const U& u) : data01_{t}, data02_{u} {}
void print(std::ostream& os) const {
os << data01_ << " : " << data02_ << std::endl;
}
};
int main() {
MyPair<double> numbers{11.11, 22.22};
numbers.print(std::cout);
}
Godbolt Listing lst-0081-godb.cpp, https://godbolt.org/z/jbafeEdoW:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/jbafeEdoW
#include <iostream>
#include <concepts> // copyable, C++20
template<std::copyable T, std::copyable U=T>
class MyPair {
T data01_;
U data02_;
public:
MyPair(const T& t,const U& u) : data01_{t}, data02_{u} {}
void print(std::ostream& os) const {
os << data01_ << " : " << data02_ << std::endl;
}
};
int main() {
MyPair<double> numbers{11.11, 22.22};
numbers.print(std::cout);
}
GodboltId:E89bav3rE
Book listing lst-0084-book.cpp:
// https://godbolt.org/z/E89bav3rE
#include <iostream>
template <typename T, size_t n=1> // Nontype parameter with default value
class FixedArray {
T data_[n] {0}; // Using nontype parameter
public:
T& operator[](size_t index) { return data_[index]; }
static constexpr size_t size() { return n; }
void print(std::ostream &os) const {
for(auto it : data_)
os << it << ' ';
os << '\n';
}
};
int main() {
FixedArray<int,10> vals {}; // n = 10
for(size_t idx=0; idx < vals.size(); ++idx) {
vals[idx] = idx+idx;
}
vals.print(std::cout); // Output: 0 2 4 6 8 10 12 14 16 18
FixedArray<double> dvals; // Default parameter for n
std::cout << dvals.size() << '\n'; // Output: 1
}
Godbolt Listing lst-0084-godb.cpp, https://godbolt.org/z/E89bav3rE:
//#(compile) c++; compiler:g141; options:-O1 -std=c++23; libs:-
// https://godbolt.org/z/E89bav3rE
#include <iostream>
template <typename T, size_t n=1> // Nontype parameter with default value
class FixedArray {
T data_[n] {0}; // Using nontype parameter
public:
T& operator[](size_t index) { return data_[index]; }
static constexpr size_t size() { return n; }
void print(std::ostream &os) const {
for(auto it : data_)
os << it << ' ';
os << '\n';
}
};
int main() {
FixedArray<int,10> vals {}; // n = 10
for(size_t idx=0; idx < vals.size(); ++idx) {
vals[idx] = idx+idx;
}
vals.print(std::cout); // Output: 0 2 4 6 8 10 12 14 16 18
FixedArray<double> dvals; // Default parameter for n
std::cout << dvals.size() << '\n'; // Output: 1
}
GodboltId:9rzsh5366
Book listing lst-0089-book.cpp:
// https://godbolt.org/z/9rzsh5366
#include <string>
#include <tuple>
#include <concepts> // copyable, C++20
template <std::copyable T, std::copyable U=T> // general case
class MyPair {
T data01_;
U data02_;
public:
MyPair(const T& t, const U& u) : data01_{t}, data02_{u} {}
};
template <std::copyable T> // partial specialization, T remains formal
class MyPair<T, std::string> { // U is specialized to string
std::tuple<T,std::string> data_;
public:
MyPair(const T& t, const std::string& str) : data_{t, str} { }
};
template <std::copyable U> // partial specialization, U remains formal
class MyPair<std::string, U> { // T is specialized to string
std::tuple<std::string, U> data_;
public:
MyPair(const std::string& str, const U& u) : data_{str, u} { }
};
int main() {
// uses partial specialization
MyPair<int,std::string> intString{1, "a"};
MyPair<std::string,int> stringInt{"b", 2};
MyPair<int,int> intInt{3,4}; // uses general case
MyPair intInt2{3,4}; // also MyPair<int,int>
MyPair<std::string,std::string> strStr{"c","d"}; // (ERR) ambiguous
}
Godbolt Listing lst-0089-godb.cpp, https://godbolt.org/z/9rzsh5366:
//#(compile) c++; compiler:g141; options:-O1 -std=c++23; libs:-
// https://godbolt.org/z/9rzsh5366
#include <string>
#include <tuple>
#include <concepts> // copyable, C++20
template <std::copyable T, std::copyable U=T> // general case
class MyPair {
T data01_;
U data02_;
public:
MyPair(const T& t, const U& u) : data01_{t}, data02_{u} {}
};
template <std::copyable T> // partial specialization, T remains formal
class MyPair<T, std::string> { // U is specialized to string
std::tuple<T,std::string> data_;
public:
MyPair(const T& t, const std::string& str) : data_{t, str} { }
};
template <std::copyable U> // partial specialization, U remains formal
class MyPair<std::string, U> { // T is specialized to string
std::tuple<std::string, U> data_;
public:
MyPair(const std::string& str, const U& u) : data_{str, u} { }
};
int main() {
// uses partial specialization
MyPair<int,std::string> intString{1, "a"};
MyPair<std::string,int> stringInt{"b", 2};
MyPair<int,int> intInt{3,4}; // uses general case
MyPair intInt2{3,4}; // also MyPair<int,int>
MyPair<std::string,std::string> strStr{"c","d"}; // (ERR) ambiguous
}
GodboltId:baPeoTbM8
Book listing lst-0090-book.cpp:
// https://godbolt.org/z/baPeoTbM8
template<> // full specialization
class MyPair<std::string, std::string> {
std::vector<std::string> data_;
public:
MyPair(const std::string& t, const std::string& u) : data_{t, u} { }
};
int main() {
// uses the full specialization:
MyPair<std::string,std::string> strStr{"c","d"};
}
Godbolt Listing lst-0090-godb.cpp, https://godbolt.org/z/baPeoTbM8:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/baPeoTbM8
template<> // full specialization
class MyPair<std::string, std::string> {
std::vector<std::string> data_;
public:
MyPair(const std::string& t, const std::string& u) : data_{t, u} { }
};
int main() {
// uses the full specialization:
MyPair<std::string,std::string> strStr{"c","d"};
}
Listing 23.35: A template with a variable number of arguments.
Book listing lst-0091-book.cpp:
// https://godbolt.org/z/eenKej9sj
#include <typeinfo> // operator typeid
#include <typeindex> // type_index
#include <map>
#include <string>
#include <iostream>
template <typename T>
void output(std::ostream& os, T val) { // output a type name
// static: initialized the first time
static const std::map<std::type_index,std::string> type_names {
{ std::type_index(typeid(const char*)), "const char*"},
{ std::type_index(typeid(char)), "char"},
{ std::type_index(typeid(int)), "int"},
{ std::type_index(typeid(double)), "double"},
{ std::type_index(typeid(bool)), "bool"},
};
const std::string name = type_names.at(std::type_index(typeid(T)));
os << name << ": " << val << '\n';
}
// recursive variadic function template:
template<typename First, typename ... Rest>
void output(std::ostream &os, First first, Rest ... rest) {
output(os, first); // single call with the foremost element
output(os, rest ...); // recursion with the rest of the elements
}
int main() {
output(std::cout, 3.1415); // normal template
output(std::cout, "end", 2, 3.14, 'A', false); // recursive variadic function
}
Godbolt Listing lst-0091-godb.cpp, https://godbolt.org/z/eenKej9sj:
//#(compile) c++; compiler:g141; options:-O1 -std=c++23; libs:-
// https://godbolt.org/z/eenKej9sj
#include <typeinfo> // operator typeid
#include <typeindex> // type_index
#include <map>
#include <string>
#include <iostream>
template <typename T>
void output(std::ostream& os, T val) { // output a type name
// static: initialized the first time
static const std::map<std::type_index,std::string> type_names {
{ std::type_index(typeid(const char*)), "const char*"},
{ std::type_index(typeid(char)), "char"},
{ std::type_index(typeid(int)), "int"},
{ std::type_index(typeid(double)), "double"},
{ std::type_index(typeid(bool)), "bool"},
};
const std::string name = type_names.at(std::type_index(typeid(T)));
os << name << ": " << val << '\n';
}
// recursive variadic function template:
template<typename First, typename ... Rest>
void output(std::ostream &os, First first, Rest ... rest) {
output(os, first); // single call with the foremost element
output(os, rest ...); // recursion with the rest of the elements
}
int main() {
output(std::cout, 3.1415); // normal template
output(std::cout, "end", 2, 3.14, 'A', false); // recursive variadic function
}
GodboltId:8oYaWYnbx
Book listing lst-0097-book.cpp:
// https://godbolt.org/z/8oYaWYnbx
#include <tuple>
#include <iostream>
template<typename ... Args>
auto conv2tuple(Args ... args) {
return std::make_tuple(args...);
}
int main() {
auto mytuple = conv2tuple("end", 2, 3.14, 'A', false);
std::cout << std::get<2>(mytuple) << '\n'; // Output: 3.14
}
Godbolt Listing lst-0097-godb.cpp, https://godbolt.org/z/8oYaWYnbx:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/8oYaWYnbx
#include <tuple>
#include <iostream>
template<typename ... Args>
auto conv2tuple(Args ... args) {
return std::make_tuple(args...);
}
int main() {
auto mytuple = conv2tuple("end", 2, 3.14, 'A', false);
std::cout << std::get<2>(mytuple) << '\n'; // Output: 3.14
}
Listing 23.36: Custom literal operators.
Book listing lst-0098-book.cpp:
// https://godbolt.org/z/cjx49ef19
namespace my {
Complex operator"" _i(const char*); // 0+ni
Complex operator"" _j(long double); // n+0i
Puzzle operator"" _puzzle(const char*, size_t);
}
using namespace my;
Complex imag4 = 4_i; // operator"" _i(const char*)
Complex real3 = 3.331_j; // operator"" _j(long double)
Puzzle p1 = "oXo" // operator"" _puzzle(const char*, size_t)
"XoX"_puzzle;
Godbolt Listing lst-0098-godb.cpp, https://godbolt.org/z/cjx49ef19:
//#(execute) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/cjx49ef19
namespace my {
Complex operator"" _i(const char*); // 0+ni
Complex operator"" _j(long double); // n+0i
Puzzle operator"" _puzzle(const char*, size_t);
}
using namespace my;
Complex imag4 = 4_i; // operator"" _i(const char*)
Complex real3 = 3.331_j; // operator"" _j(long double)
Puzzle p1 = "oXo" // operator"" _puzzle(const char*, size_t)
"XoX"_puzzle;
Listing 23.37: Which literal leads to which operator call?
Book listing lst-0099-book.cpp:
// https://godbolt.org/z/Mevoshb3o
namespace lits {
long double operator"" _w(long double);
string operator"" _w(const char16_t*, size_t);
unsigned operator"" _w(const char*);
}
int main() {
using namespace lits;
1.2_w; // operator"" _w(long double), with (1.2L)
u"one"_w; // operator"" _w(char16_t, size_t), with (u"one", 3)
12_w; // operator"" _w(const char*), with "12"
"two"_w; // (ERR) operator"" _w(const char*, size_t) not defined
}
Godbolt Listing lst-0099-godb.cpp, https://godbolt.org/z/Mevoshb3o:
//#(execute) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/Mevoshb3o
namespace lits {
long double operator"" _w(long double);
string operator"" _w(const char16_t*, size_t);
unsigned operator"" _w(const char*);
}
int main() {
using namespace lits;
1.2_w; // operator"" _w(long double), with (1.2L)
u"one"_w; // operator"" _w(char16_t, size_t), with (u"one", 3)
12_w; // operator"" _w(const char*), with "12"
"two"_w; // (ERR) operator"" _w(const char*, size_t) not defined
}
Listing 23.38: A template for literals of exact length two.
Book listing lst-0100-book.cpp:
// https://godbolt.org/z/5rdzn8YP4
namespace lits {
// general template
template<char...> int operator"" _bin2();
// specializations
template<> int operator"" _bin2<'0','0'>() { return 0; }
template<> int operator"" _bin2<'0','1'>() { return 1; }
template<> int operator"" _bin2<'1','0'>() { return 2; }
template<> int operator"" _bin2<'1','1'>() { return 3; }
}
int main() {
using namespace lits;
int one = 01_bin2;
int three = 11_bin2;
}
Godbolt Listing lst-0100-godb.cpp, https://godbolt.org/z/5rdzn8YP4:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/5rdzn8YP4
namespace lits {
// general template
template<char...> int operator"" _bin2();
// specializations
template<> int operator"" _bin2<'0','0'>() { return 0; }
template<> int operator"" _bin2<'0','1'>() { return 1; }
template<> int operator"" _bin2<'1','0'>() { return 2; }
template<> int operator"" _bin2<'1','1'>() { return 3; }
}
int main() {
using namespace lits;
int one = 01_bin2;
int three = 11_bin2;
}
Listing 23.39: Recursive definition for arbitrary literal lengths.
Book listing lst-0101-book.cpp:
// https://godbolt.org/z/sbxojqjqs
namespace lits {
// Template helper function for one argument
template<char C> int bin(); // general case
template<> int bin<'1'>() { return 1; } // Specialization
template<> int bin<'0'>() { return 0; } // Specialization
// Template helper function for two or more arguments
template<char C, char D, char... ES>
int bin() {
return bin<C>() << (sizeof...(ES)+1) | bin<D,ES...>(); // Bit-Shift, Bit-Or
}
// actual operator""
template<char...CS> int operator"" _bin()
{ return bin<CS...>(); };
}
int main() {
using namespace lits;
int one = 1_bin;
int eight = 1000_bin;
int nine = 1001_bin;
int ten = 1010_bin;
int eleven = 1011_bin;
int one_hundred_twenty_eight = 10000000_bin;
}
Godbolt Listing lst-0101-godb.cpp, https://godbolt.org/z/sbxojqjqs:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/sbxojqjqs
namespace lits {
// Template helper function for one argument
template<char C> int bin(); // general case
template<> int bin<'1'>() { return 1; } // Specialization
template<> int bin<'0'>() { return 0; } // Specialization
// Template helper function for two or more arguments
template<char C, char D, char... ES>
int bin() {
return bin<C>() << (sizeof...(ES)+1) | bin<D,ES...>(); // Bit-Shift, Bit-Or
}
// actual operator""
template<char...CS> int operator"" _bin()
{ return bin<CS...>(); };
}
int main() {
using namespace lits;
int one = 1_bin;
int eight = 1000_bin;
int nine = 1001_bin;
int ten = 1010_bin;
int eleven = 1011_bin;
int one_hundred_twenty_eight = 10000000_bin;
}
Listing 23.40: The new if constexpr saves function specializations.
Book listing lst-0102-book.cpp:
// https://godbolt.org/z/KvsGh4f1v
namespace lits {
// Template helper function for one argument
template<char C> int bin() { // general case
if constexpr (C=='0') return 0;
else if constexpr (C=='1') return 1;
}
// Template helper function for two or more arguments
// …
}
Godbolt Listing lst-0102-godb.cpp, https://godbolt.org/z/KvsGh4f1v:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/KvsGh4f1v
namespace lits {
// Template helper function for one argument
template<char C> int bin() { // general case
if constexpr (C=='0') return 0;
else if constexpr (C=='1') return 1;
}
// Template helper function for two or more arguments
// …
}
Listing 23.41: Fold expressions make variadic templates simpler.
Book listing lst-0103-book.cpp:
// https://godbolt.org/z/cPoEjqzM7
#include <iostream>
#include <string>
namespace lits {
// operator"" _sx
template<char...CS> std::string operator"" _sx() {
return (std::string{} + ... + CS); // a fold expression
};
}
int main() {
using namespace lits;
std::cout << 10000000_sx << '\n'; // Output: 10000000
std::cout << 10'000'000_sx << '\n'; // Output: 10'000'000
std::cout << 0x00af_sx << '\n'; // Output: 0x00af
std::cout << 0x0'c'0'a'f_sx << '\n'; // Output: 0x0'c'0'a'f
std::cout << 007_sx << '\n'; // Output: 007
std::cout << 0b01_sx << '\n'; // Output: 0b01
}
Godbolt Listing lst-0103-godb.cpp, https://godbolt.org/z/cPoEjqzM7:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/cPoEjqzM7
#include <iostream>
#include <string>
namespace lits {
// operator"" _sx
template<char...CS> std::string operator"" _sx() {
return (std::string{} + ... + CS); // a fold expression
};
}
int main() {
using namespace lits;
std::cout << 10000000_sx << '\n'; // Output: 10000000
std::cout << 10'000'000_sx << '\n'; // Output: 10'000'000
std::cout << 0x00af_sx << '\n'; // Output: 0x00af
std::cout << 0x0'c'0'a'f_sx << '\n'; // Output: 0x0'c'0'a'f
std::cout << 007_sx << '\n'; // Output: 007
std::cout << 0b01_sx << '\n'; // Output: 0b01
}
Listing 23.42: Whether preprocessed or raw is better depends on the application.
Book listing lst-0104-book.cpp:
// https://godbolt.org/z/Yd4sser5j
#include <complex>
// raw form
int operator"" _dual(const char*);
int answer = 101010_dual; // decimal 42
// preprocessed form
std::complex<long double> operator"" _i(long double d) {
return std::complex<long double>(0, d);
}
auto val = 3.14_i; // val = std::complex<long double>(0, 3.14)
Godbolt Listing lst-0104-godb.cpp, https://godbolt.org/z/Yd4sser5j:
//#(execute) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/Yd4sser5j
#include <complex>
// raw form
int operator"" _dual(const char*);
int answer = 101010_dual; // decimal 42
// preprocessed form
std::complex<long double> operator"" _i(long double d) {
return std::complex<long double>(0, d);
}
auto val = 3.14_i; // val = std::complex<long double>(0, 3.14)