Created
October 1, 2022 06:52
-
-
Save tyqualters/548208d67fccf72a1c0bf177eb41122a to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| /** | |
| * @file chain.cc | |
| * @author Ty Qualters (contact@tyqualters.com) | |
| * @brief C++ example demonstrating the use of method chaining in a class. | |
| * @version 0.1 | |
| * @date 2022-09-30 | |
| * | |
| * @copyright Copyright (c) 2022 | |
| * | |
| */ | |
| #include <iostream> // std::cout, std::endl | |
| #include <string> // std::string | |
| #include <sstream> // std::stringstream | |
| #include <cassert> // assert | |
| #define SUCCESS return 0; | |
| #define println(x) std::cout << x << std::endl | |
| // A simple class to wrap variables and ensure they are initialized. | |
| template<class T> | |
| class initializer_guard { | |
| public: | |
| initializer_guard() = default; | |
| // Copy; Set the value of the variable. | |
| auto set_value(T new_value) -> void { | |
| this->value = new_value; | |
| this->initialized = true; | |
| } | |
| // Reference; Get the value of the variable. | |
| auto get_value() -> T& { | |
| return this->value; | |
| } | |
| // Initialize a new instance of the variable using its type constructor. | |
| template<class... Types> | |
| auto construct(Types... args) -> void { | |
| this->value = T(args...); | |
| this->initialized = true; | |
| } | |
| // Conditional; The variable has or has not been initialized. | |
| auto was_initialized() -> bool { | |
| return this->initialized; | |
| } | |
| protected: | |
| T value; | |
| bool initialized = false; | |
| }; | |
| class Person { | |
| public: | |
| Person() = default; | |
| // Reference; Set the name and return the same object. | |
| auto setName(std::string new_name) -> Person& { | |
| this->name.set_value(new_name); | |
| return *this; | |
| } | |
| // Reference; Set the age and return the same object. | |
| auto setAge(int new_age) -> Person& { | |
| this->age.set_value(new_age); | |
| return *this; | |
| } | |
| // Reference; Set the living status and return the same object. | |
| auto setAlive(bool is_alive) -> Person& { | |
| this->living.set_value(is_alive); | |
| return *this; | |
| } | |
| // String; A basic toString implementation. | |
| auto toString() -> std::string { | |
| // Assert provides great conditional error checking for debugging. | |
| // It's used to ensure some condition is met. | |
| assert(this->name.was_initialized()); | |
| assert(this->age.was_initialized()); | |
| if(!living.was_initialized()) { | |
| // Assume the person is alive. | |
| living.set_value(true); | |
| } | |
| // StringStream is essentially just C++'s version of Java's StringBuilder. | |
| std::stringstream ss; | |
| ss << "Name: " << this->name.get_value() << std::endl; | |
| ss << "Age: " << this->age.get_value() << std::endl; | |
| ss << "Is alive: " << (this->living.get_value() ? "Yes" : "No") << std::endl; | |
| return ss.str(); | |
| } | |
| private: | |
| initializer_guard<std::string> name; | |
| initializer_guard<int> age; | |
| initializer_guard<bool> living; | |
| }; | |
| auto main() noexcept -> int { | |
| Person person = Person() | |
| .setName("John") | |
| .setAge(15) | |
| .setAlive(true); | |
| println(person.toString()); | |
| SUCCESS | |
| } |
Author
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
One note to keep in mind is that with the
initializer_guardclass, theget_valuemethod could be implemented to return astd::optional<T>and the subsequent value orstd::nulloptif not initialized.