GCC Code Coverage Report


Directory: ./
File: Verbose.hpp
Date: 2026-03-21 20:51:59
Exec Total Coverage
Lines: 40 40 100.0%
Functions: 53 53 100.0%
Branches: 26 45 57.8%

Line Branch Exec Source
1 #pragma once
2 #include <iostream>
3 #include <string>
4 #include <tuple>
5
6 // Forward declarations
7 template <typename T>
8 class Verbose;
9
10 template <typename T>
11 Verbose<T> make_verbose(std::string name, T&& obj);
12
13 template <typename T>
14 void swap(Verbose<T>&, Verbose<T>&) noexcept;
15
16 template <typename T>
17 std::ostream& operator<<(std::ostream&, const Verbose<T>&);
18
19 ////////////////////////////////////////////////////////////////////////////////
20
21 // Make any class verbose
22 template <typename T = std::tuple<>>
23 class Verbose : public T {
24 public:
25 template <typename... Args>
26 Verbose(std::string name, Args&&... args); // delegating constructor
27 Verbose(const Verbose& other); // copy constructor
28 Verbose(Verbose&& other) noexcept; // move constructor
29 Verbose& operator=(const Verbose& other); // copy assignment
30 Verbose& operator=(Verbose&& other) noexcept; // move assignment
31 ~Verbose() noexcept; // destructor NOLINT
32 friend void swap<>(Verbose&, Verbose&) noexcept; // non-member swap
33
34 std::string& name() noexcept;
35 [[nodiscard]] const std::string& name() const noexcept;
36
37 private:
38 std::string name_{};
39 };
40
41 ////////////////////////////////////////////////////////////////////////////////
42
43 template <typename T>
44 4 Verbose<T> make_verbose(std::string name, T&& obj) {
45
1/2
✓ Branch 5 taken 2 times.
✗ Branch 6 not taken.
12 return Verbose<T>{std::move(name), std::forward<T>(obj)};
46 }
47
48 template <typename T>
49 void swap(Verbose<T>& left, Verbose<T>& right) noexcept {
50 std::cout << left.name() << ": swap left=" << &left //
51 << " right=" << &right << std::endl;
52 using std::swap; // enable Argument Dependent Lookup
53 swap(static_cast<T&>(left), static_cast<T&>(right));
54 swap(left.name_, right.name_);
55 }
56
57 template <typename T>
58 58 std::ostream& operator<<(std::ostream& s, const Verbose<T>& v) {
59 58 return operator<<(s, v.name());
60 }
61
62 ////////////////////////////////////////////////////////////////////////////////
63
64 template <typename T>
65 template <typename... Args>
66 238 Verbose<T>::Verbose(std::string name, Args&&... args) :
67 544 T{std::forward<Args>(args)...}, name_(std::move(name)) {
68
8/12
✓ Branch 4 taken 136 times.
✓ Branch 5 taken 60 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 136 times.
✓ Branch 8 taken 60 times.
✗ Branch 9 not taken.
✓ Branch 13 taken 136 times.
✓ Branch 14 taken 60 times.
✗ Branch 15 not taken.
✓ Branch 19 taken 136 times.
✓ Branch 20 taken 60 times.
✗ Branch 21 not taken.
238 std::cout << name_ << ": constructor this=" << this << std::endl;
69 238 }
70
71 template <typename T>
72 15 Verbose<T>::Verbose(const Verbose& other) :
73
4/8
✓ Branch 6 taken 13 times.
✗ Branch 7 not taken.
✓ Branch 11 taken 13 times.
✗ Branch 12 not taken.
✓ Branch 16 taken 2 times.
✗ Branch 17 not taken.
✓ Branch 24 taken 2 times.
✗ Branch 25 not taken.
45 T{other}, name_{std::string("copy constructed from ") + other.name_} {
74
6/9
✓ Branch 4 taken 13 times.
✓ Branch 5 taken 2 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 13 times.
✓ Branch 8 taken 2 times.
✗ Branch 9 not taken.
✓ Branch 13 taken 13 times.
✓ Branch 14 taken 2 times.
✗ Branch 15 not taken.
15 std::cout << name_ << ": copy constructor this=" << this
75
3/6
✓ Branch 2 taken 15 times.
✗ Branch 3 not taken.
✓ Branch 8 taken 15 times.
✗ Branch 9 not taken.
✓ Branch 14 taken 15 times.
✗ Branch 15 not taken.
15 << " other=" << &other << std::endl;
76 15 }
77
78 // Note that other.name_ is *not* moved from.
79 template <typename T>
80 10 Verbose<T>::Verbose(Verbose&& other) noexcept :
81 13 T{std::move(other)},
82 33 name_{std::string("move constructed from ") + other.name_} {
83 10 std::cout << name_ << ": move constructor this=" << this
84 10 << " other=" << &other << std::endl;
85 10 other.name_ += " (moved)";
86 10 }
87
88 template <typename T>
89 5 Verbose<T>& Verbose<T>::operator=(const Verbose& other) {
90 4 T::operator=(other);
91 5 std::cout << name_ << ": copy assignment this=" << this
92 5 << " other=" << &other << std::endl;
93
4/8
✓ Branch 7 taken 1 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 4 times.
✗ Branch 10 not taken.
✓ Branch 11 taken 1 times.
✗ Branch 12 not taken.
✓ Branch 13 taken 4 times.
✗ Branch 14 not taken.
15 name_ = std::string("copy assigned from ") + other.name_;
94 5 return *this;
95 }
96
97 // Note that other.name_ is *not* moved from.
98 template <typename T>
99 19 Verbose<T>& Verbose<T>::operator=(Verbose&& other) noexcept {
100 38 T::operator=(std::move(other));
101 19 std::cout << name_ << ": move assignment this=" << this
102 19 << " other=" << &other << std::endl;
103 57 name_ = std::string("move assigned from ") + other.name_;
104 19 other.name_ += " (moved)";
105 19 return *this;
106 }
107
108 template <typename T>
109 304 Verbose<T>::~Verbose() noexcept {
110 282 std::cout << name_ << ": destructor this=" << this << std::endl;
111 406 }
112
113 template <typename T>
114 298 std::string& Verbose<T>::name() noexcept {
115 298 return name_;
116 }
117
118 template <typename T>
119 322 const std::string& Verbose<T>::name() const noexcept {
120 322 return name_;
121 }
122