Skip to content

Instantly share code, notes, and snippets.

@tyqualters
Created October 1, 2022 06:52
Show Gist options
  • Select an option

  • Save tyqualters/548208d67fccf72a1c0bf177eb41122a to your computer and use it in GitHub Desktop.

Select an option

Save tyqualters/548208d67fccf72a1c0bf177eb41122a to your computer and use it in GitHub Desktop.
/**
* @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
}
@tyqualters
Copy link
Author

One note to keep in mind is that with the initializer_guard class, the get_value method could be implemented to return a std::optional<T> and the subsequent value or std::nullopt if not initialized.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment