Putting it together
- C++ course
- Advanced
- Lesson 83/83
- 6 min
Combine all layers into a working mini framework.
Putting it together
In the final lesson we combine all layers: the skeleton, modern C++ data processing, the concurrency parallel sum, and the design pattern tasks. We now have a working mini framework.
All the code from previous lessons is in place: the Framework class, process_data, parallel_sum, Logger, TaskFactory. In this lesson we add an integration message at the end of the run method. This message confirms that all layers ran successfully. The output grows as the accumulation of four lessons: the ready message, the sum, the parallel sum, the log, and the integration message.
Final integration message
At the end of the run method, we will print a message confirming that all layers ran. This message comes after the execute() call.
Example: std::cout << std::endl << "run complete";. This line writes the integration message on a new line below the previous [log] output. This way the output shows the accumulation of four lessons: "Project ready", "sum: 4", "parallel: 4", "[log] task done" and "run complete". The framework is now fully working with all layers.
Practice Add the final integration message
In the run method, after the t->execute(); line, add std::cout << std::endl << "run complete";. Do not touch the other code.
Starter code
#include <iostream>
#include <string>
#include <vector>
#include <ranges>
#include <algorithm>
#include <concepts>
#include <thread>
#include <atomic>
#include <memory>
class Logger {
public:
static Logger& instance() {
static Logger inst;
return inst;
}
void log(const std::string& msg) { std::cout << "[log] " << msg; }
private:
Logger() = default;
};
class Task {
public:
virtual ~Task() = default;
virtual void execute() = 0;
};
class PrintTask : public Task {
public:
PrintTask(const std::string& m) : msg_(m) {}
void execute() override { Logger::instance().log(msg_); }
private:
std::string msg_;
};
class TaskFactory {
public:
static std::unique_ptr<Task> makePrint(const std::string& m) {
return std::make_unique<PrintTask>(m);
}
};
class Framework {
public:
int run();
template<std::integral T>
int process_data(const std::vector<T>& data);
int parallel_sum(const std::vector<int>& data);
};
template<std::integral T>
int Framework::process_data(const std::vector<T>& data) {
int sum = 0;
for (auto x : data | std::views::filter([](T v) { return v > 0; })) {
sum += x;
}
return sum;
}
int Framework::parallel_sum(const std::vector<int>& data) {
std::atomic<int> total{0};
std::thread t1([&]() { for (auto x : data) if (x > 0) total += x; });
t1.join();
return total;
}
int Framework::run() {
std::cout << "Project ready" << std::endl;
std::vector<int> data{1, -2, 3};
std::cout << "sum: " << process_data(data) << std::endl;
std::cout << "parallel: " << parallel_sum(data) << std::endl;
auto t = TaskFactory::makePrint("task done");
t->execute();
// write the final integration message
return 0;
}
int main() {
Framework fw;
fw.run();
return 0;
}Sample solution
#include <iostream>
#include <string>
#include <vector>
#include <ranges>
#include <algorithm>
#include <concepts>
#include <thread>
#include <atomic>
#include <memory>
class Logger {
public:
static Logger& instance() {
static Logger inst;
return inst;
}
void log(const std::string& msg) { std::cout << "[log] " << msg; }
private:
Logger() = default;
};
class Task {
public:
virtual ~Task() = default;
virtual void execute() = 0;
};
class PrintTask : public Task {
public:
PrintTask(const std::string& m) : msg_(m) {}
void execute() override { Logger::instance().log(msg_); }
private:
std::string msg_;
};
class TaskFactory {
public:
static std::unique_ptr<Task> makePrint(const std::string& m) {
return std::make_unique<PrintTask>(m);
}
};
class Framework {
public:
int run();
template<std::integral T>
int process_data(const std::vector<T>& data);
int parallel_sum(const std::vector<int>& data);
};
template<std::integral T>
int Framework::process_data(const std::vector<T>& data) {
int sum = 0;
for (auto x : data | std::views::filter([](T v) { return v > 0; })) {
sum += x;
}
return sum;
}
int Framework::parallel_sum(const std::vector<int>& data) {
std::atomic<int> total{0};
std::thread t1([&]() { for (auto x : data) if (x > 0) total += x; });
t1.join();
return total;
}
int Framework::run() {
std::cout << "Project ready" << std::endl;
std::vector<int> data{1, -2, 3};
std::cout << "sum: " << process_data(data) << std::endl;
std::cout << "parallel: " << parallel_sum(data) << std::endl;
auto t = TaskFactory::makePrint("task done");
t->execute();
std::cout << std::endl << "run complete";
return 0;
}
int main() {
Framework fw;
fw.run();
return 0;
}Expected output
Project ready sum: 4 parallel: 4 [log] task done run complete
Questions and answers
Review the lesson questions together with their answers. To test yourself, solve the lesson interactively.
1 the run call
Framework fw; fw.____();
Framework fw; fw.run();
Explanation: fw.run() starts the framework.
2 What does integration mean?
- Deleting code
- Adding a new class
- Running all layers together to get an integrated application Correct answer
- Skipping compilation
Explanation: Integration means running all layers together to get an integrated application.
3 Match each layer to its role
| Term | Meaning |
|---|---|
process_data |
Data processing |
parallel_sum |
Parallel sum |
Logger |
Logging |
main() |
Integrated entry |