How to instantiate input based strategy pattern - c++

The instantiation of strategy pattern is usually completely overlooked by the examples. Let's assume there is an input that defines which class to use. We'd have something along the lines of:
class Strategy {
Strategy(){}
virtual void runAlgorithm() = 0;
};
class A : public Strategy {
A () {}
static bool isA(char input){ return input == 'A'; }
void runAlgorithm { /* Do A algorithm */ }
};
class B : public Strategy {
B () {}
static bool isB(char input){ return input == 'B'; }
void runAlgorithm { /* Do B algorithm */ }
};
// Other algorithms
Strategy* createStrat(char input){
Strategy* instance;
// Define which algorithm to use
if (A::isA(input)) {
instance = A();
} else if (B::isB(input)) {
instance = B();
} ...
// Run algorithm
instance.runAlgorithm();
return instance;
}
As you can see, if we have multiple different algorithms this if/switch can get pretty big. Is there a pattern to make this code easier to humanly parse (i.e., a for loop and a call) without adding an array of pairs? The question could also be expanded to "How to instantiate an input based strategy pattern?"
Do not limit to this code, as it is just an example.

Ok, if you know all your strategies in advance you can use a very simple meta-programming recursion to unroll your if-else chains automatically. Here we go:
#include <string_view>
#include <iostream>
#include <exception>
#include <memory>
struct Strategy {
Strategy(){}
virtual void runAlgorithm() = 0;
};
struct A : public Strategy {
A () {std::cout << "Creating A" << std::endl;}
static constexpr std::string_view id(){
return std::string_view("A");
}
void runAlgorithm() { /* Do A algorithm */ }
};
struct B : public Strategy {
B () {std::cout << "Creating B" << std::endl;}
static constexpr std::string_view id(){
return std::string_view("B");
}
void runAlgorithm() { /* Do B algorithm */ }
};
struct C : public Strategy {
C () {std::cout << "Creating C" << std::endl;}
static constexpr std::string_view id(){
return std::string_view("C");
}
void runAlgorithm() { /* Do C algorithm */ }
};
// the if else chains are constructed by recursion
template <class Head, class... Tail>
struct factory {
static std::unique_ptr<Strategy> call(std::string id) {
if(Head::id() == id) return std::make_unique<Head>();
else return factory<Tail...>::call(id);
}
};
// specialization to end the recursion
// this throws an exception, but you can adapt it to your needs
template <class Head>
struct factory<Head> {
static std::unique_ptr<Strategy> call(std::string id) {
if(Head::id() == id) return std::make_unique<Head>();
else throw std::invalid_argument("The strategy id you selected was not found.");
}
};
// here is your factory which can create instances of A,B,C based only on the runtime id
using my_factory = factory<A,B,C>;
int main() {
auto Astrategy = my_factory::call("A");
auto Bstrategy = my_factory::call("B");
auto Cstrategy = my_factory::call("C");
my_factory::call("D"); // exception thrown
}
Live code here
Edit
Edited to account for smart pointers and error checking as Jarod42 suggested.

Yes there is a solution for that. There are couple ways to do it. Template as in other class or this way:
class StrategyMaker {
public:
void register(std::funcion<bool(char)> predicate,
std::function<std::unique_ptr<Strategy>(char)> factory) {
mFactories.push_back(std::make_pair(std::move(predicate), std::move(factory)));
}
std::unique_ptr<Strategy> create(char ch) {
for (auto pair & : mFactories) {
if (pair.first(ch)) {
return pair.second(ch);
}
}
return {};
}
private:
std::vector<std::pair<std::funcion<bool(char)>,
std::function<std::unique_ptr<Strategy>(char)>>> mFactories;
};
StrategyMaker maker;
maker.register([](char ch){ return input == 'A'; },
[](char ch){ return std::unique_ptr(new A); });
Once I've seen nice article showing how to make it fully automatic. I've found something like this (I'm not 100% sure this is what I read some time ago).

Related

CRTP used with std::any vs virtual functions

I am trying to create a compile time polymorphism design that will not require virtual functions with all their drawbacks. However I am struggling with creating simple, effective and easy to understand container that can simulate the ability to hold derived class in it's base class container. My previous attempts with compile time variadic vectors were working, but the code was huge mess. This solutions seems cleaner to me. I have simple code that implements basic CTRP. However I created a runtime container that is storing std::any objects and then based on the type of the object, I can define the action that is supposed to be taken. I have few questions.
How does the usage of std::any and subsequent any_cast<>() hinder the performance compared to the usage of virtual functions?
Is the usage of std::any valid in this situation?
Is there a better way to implement such container?
Is there a way to force implementation as it is with virtual functions (by using virtual <type> foo() = 0)?
Is it a good idea to create an object that will be a CRTP handler? So I will not have a function for CRTP call, but an object, that can manage those calls?
Thank you.
Here is the base class:
class base {
private:
base() = default;
friend T;
T& implementation = static_cast<T&>(*this);
public:
auto do_stuff() {
return implementation.do_stuff();
}
};
Here is the implementation:
#include <iostream>
class implementation_a : public base<implementation_a> {
public:
auto do_stuff() {
std::cout << 42 << std::endl;
}
};
class implementation_b : public base<implementation_b> {
public:
auto do_stuff() {
return 420;
}
};
Here's the container:
#include <vector>
#include <any>
class crtp_vector {
private:
std::vector<std::any> vec;
public:
auto begin() {
return vec.begin();
}
auto end() {
return vec.end();
}
auto empty() {
return vec.empty();
}
auto size() {
return vec.size();
}
void clear() {
vec.clear();
}
void push_back(const std::any& val) {
vec.push_back(val);
}
auto emplace_back(const std::any& val) {
vec.emplace_back(val);
}
};
Here's the main:
#include "crtp_container.h"
#include <utility>
/* crtp call handler */
template <typename T>
auto crtp_call(T& val) {
return val.do_stuff();
}
int main() {
crtp_vector vec;
implementation_a A;
implementation_b B;
vec.push_back(A);
vec.push_back(B);
for(auto &member : vec) {
if(member.type().name() == typeid(implementation_a).name()) {
crtp_call(std::any_cast<implementation_a&>(member));
}
else if(member.type().name() == typeid(implementation_b).name()) {
std::cout << crtp_call(std::any_cast<implementation_b&>(member)) << std::endl;
}
else {
std::cerr << "no viable type conversion" << std::endl;
}
}
return 0;
}
You make it way too complicated. The code shown doesn't use base in any way; nothing would change if you simply remove it entirely. Even though you keep saying "CRTP", you aren't actually relying on CRTP for anything.
The code doesn't use the ability of std::any to hold any type; it's only used to hold one of a fixed set of types known at compile time. std::variant is better for this.
All told, the example boils down to this:
class implementation_a {
public:
auto do_stuff() {
std::cout << 42 << std::endl;
}
};
class implementation_b {
public:
auto do_stuff() {
std::cout << 420 << std::endl;
return 420;
}
};
int main() {
implementation_a A;
implementation_b B;
std::vector<std::variant<implementation_a, implementation_b>> vec;
vec.push_back(A);
vec.push_back(B);
for(auto &member : vec) {
std::visit([](auto& elem) { elem.do_stuff(); }, member);
}
return 0;
}
Demo

Iterate through a map of std::variant

I'm experimenting with C++17's std::variant to store data of multiple types in a map. The use-case here is to have a map of controllers of generic types (but bound by std::variant) that I can iterate through and call methods of.
In below example,
#include <iostream>
#include <map>
#include <variant>
class ControlA {
public:
void specificToA() { std::cout << "A" << std::endl; }
};
class ControlB {
public:
void specificToB() { std::cout << "B" << std::endl; }
};
template<typename T>
class ControlItem{
T* control;
public:
ControlItem() = default;
~ControlItem() = default;
void doStuff() {
if constexpr (std::is_same_v<T, ControlA>) {
control->specificToA();
}
if constexpr (std::is_same_v<T, ControlB>) {
control->specificToB();
}
}
};
class MyClass {
public:
void cycleThroughMap();
std::map<std::string, std::variant<ControlItem<ControlA>, ControlItem<ControlB>>> controlMap;
};
The heuristic method for this would be to get the mapped value of each declared type like:
void MyClass::cycleThroughMap() {
for (auto controlItem : controlMap) {
if (auto control = std::get_if<ControlItem<ControlA>>(&controlItem.second)) {
control->doStuff();
} else if (auto control = std::get_if<ControlItem<ControlB>>(&controlItem.second)) {
control->doStuff();
} else
std::cout << "Unknown type!" << std::endl;
}
}
This works but feels like it's not meant to exist.
Can std::variant be used for this? Is it a bad idea from the start, should I use inheritance and voilĂ ?
Can std::variant be used for this?
Yes. Your code is primed for using a variant effectively. The variant holds types with the same implicit interface. It's a perfect opportunity to use std::visit with a generic lambda.
void MyClass::cycleThroughMap() {
for (auto& [ key, control ] : controlMap) {
std::visit([](auto&& c) {
c.doStuff();
}, control);
}
}
I also took the liberty of replacing the pair access with a structured binding. For some added simplicity.
Another way to structure the code - removes the need for get_if. Comments inline:
#include <map>
#include <variant>
#include <iostream>
class ControlA {
public:
void specificToA() { std::cout << "A" << std::endl; }
};
// consistent free-function interface for each operation type allows ADL lookup
void adlDoStuff(ControlA& c)
{
// but with different implementation details
c.specificToA();
}
class ControlB {
public:
void specificToB() { std::cout << "B" << std::endl; }
};
// consistent free-function interface for each operation type allows ADL lookup
void adlDoStuff(ControlB& c)
{
// but with different implementation details
c.specificToB();
}
template<typename T>
class ControlItem{
T* control;
public:
ControlItem() = default;
~ControlItem() = default;
void doStuff() {
// invoke the adl-friendly free functions.
adlDoStuff(*control);
}
};
class MyClass {
public:
void cycleThroughMap();
std::map<std::string, std::variant<ControlItem<ControlA>, ControlItem<ControlB>>> controlMap;
};
void MyClass::cycleThroughMap() {
// use std::visit. Every type of control will have the .doStuff interface
for (auto&& elem : controlMap) {
std::visit([](auto&& control)
{
control.doStuff();
}, elem.second);
}
}

How to mark which class to cast to in c++?

I am looking for some way to mark the class I want to cast to. I am quite new here on the site so please feel free to improve tags or other things.
For example, if I have:
template<class C>
class Rotateable
{
virtual void C Rotate() = 0;
};
class Circle : public Rotateable<Circle>
{
Circle Rotate() { /*impl here*/ }
};
class Square : public Rotateable<Square>
{
Square Rotate() { /*impl here*/ }
};
If I have a list or array of Rotateables, how can I store somewhere (in Rotateable?) the information of what class to try and cast to, in a way that I can access at runtime?
You can't have a virtual whose return type changes. But you can have type identifiers on polymorphic classes that tell you which class to cast to before calling the function. Take a look at something like this as the basic idea. (This is c++14 code. Feel free to strip out any parts that don't work for you if you aren't using c++14 features.)
#include <iostream>
#include <memory>
#include <vector>
size_t generate_id()
{
static size_t id = 0;
return id++;
}
template <typename T>
size_t type_id()
{
static size_t id = generate_id();
return id;
}
class BaseRotatable
{
public:
template <typename T>
bool is()
{
return type_id<T>() == type();
}
virtual size_t type() = 0;
};
template <typename T>
class Rotatable : public BaseRotatable
{
public:
size_t type() override
{
return type_id<T>();
}
};
class Circle : public Rotatable<Circle>
{
public:
Circle Rotate()
{
return *this; // Make this do something fancier.
}
};
class Square : public Rotatable<Square>
{
public:
Square Rotate()
{
return *this; // Make this do something fancier.
}
};
template <typename T, typename... Args>
std::unique_ptr<BaseRotatable> factory(Args... args)
{
T* ptr = new T(args...);
return std::unique_ptr<BaseRotatable>{dynamic_cast<BaseRotatable*>(ptr)};
}
int main() {
// Build a vector of rotatables.
std::vector<std::unique_ptr<BaseRotatable>> rotatables;
rotatables.emplace_back(factory<Circle>());
rotatables.emplace_back(factory<Square>());
for (auto& rotatable : rotatables)
{
// You can also use a switch here.
if (rotatable->is<Circle>())
{
Circle& circle = *dynamic_cast<Circle*>(rotatable.get());
auto new_circle = circle.Rotate();
std::cout << "Type id: " << new_circle.type() << std::endl;
}
else if (rotatable->is<Square>())
{
Square& square = *dynamic_cast<Square*>(rotatable.get());
auto new_square = square.Rotate();
std::cout << "Type id: " << new_square.type() << std::endl;
}
}
return 0;
}

How to handle Observables with different state-value types in the Observer

(Context and question first, skeleton code at the bottom of the post)
We are creating and implementing a C++ framework to use in environments like Arduino.
For this I want to use the Observer pattern, where any component interested in state-changes of sensors (Observables) can register itself and it will get notified of those changes by the Observable calling the notification() method of the Observer with itself as a parameter.
One Observer can observe multiple Observables, and vice versa.
The problem lies in the fact that the Observer needs to extract the current state of the Observable and do something with it, and this current state can take all forms and sizes, depending on the particular sensor that is the Observable.
It can of course be ordinal values, which are finite and can be coded out, like I did in the code below with the method getValueasInt() but it can also be sensor-specific structures, i.e. for a RealTimeClock, which delivers a struct of date and time values. The struct are of course defined at compile time, and fixed for a specific sensor.
My question: What is the most elegant, and future-modification proof solution or pattern for this ?
Edit: Note that dynamic_cast<> constructions are not possible because of Arduino limitations
I have created the following class-hierarchy (skeleton code):
class SenseNode
{
public:
SenseNode() {};
SenseNode(uint8_t aNodeId): id(aNodeId) {}
virtual ~SenseNode() {}
uint8_t getId() { return id; };
private:
uint8_t id = 0;
};
class SenseStateNode : virtual public SenseNode
{
public:
SenseStateNode(uint8_t aNodeId) : SenseNode(aNodeId) {}
virtual ~SenseStateNode() {}
/** Return current node state interpreted as an integer. */
virtual int getValueAsInt();
};
class SenseObservable: public SenseStateNode
{
public:
SenseObservable(uint8_t aNodeId);
virtual ~SenseObservable();
/** Notify all interested observers of the change in state by calling Observer.notification(this) */
virtual void notifyObservers();
protected:
virtual void registerObserver(SenseObserver *);
virtual void unregisterObserver(SenseObserver *);
};
class SenseObserver: virtual public SenseNode
{
public:
SenseObserver() {};
virtual ~SenseObserver();
/** Called by an Observable that we are observing to inform us of a change in state */
virtual void notification(SenseObservable *observable) {
int v = observable->getValueAsInt(); // works like a charm
DateTime d = observable-> ???? // How should i solve this elegantly?
};
};
My previous answer does not take into account that the same observer might me registered with different observables. I'll try to give a full solution here. The solution is very flexible and scalable but a bit hard to understand as it involves template meta programming (TMP). I'll start by outlining what the end result will look like and then move into the TMP stuff. Brace yourself, this is a LONG answer. Here we go:
We first have, for the sake of the example, three observables, each with its own unique interface which we will want later to access from the observer.
#include <vector>
#include <algorithm>
#include <iostream>
#include <unordered_map>
#include <string>
class observable;
class observer {
public:
virtual void notify(observable& x) = 0;
};
// For simplicity, I will give some default implementation for storing the observers
class observable {
// assumping plain pointers
// leaving it to you to take of memory
std::vector<observer*> m_observers;
public:
observable() = default;
// string id for identifying the concrete observable at runtime
virtual std::string id() = 0;
void notifyObservers() {
for(auto& obs : m_observers) obs->notify(*this);
}
void registerObserver(observer* x) {
m_observers.push_back(x);
}
void unregisterObserver(observer*) {
// give your implementation here
}
virtual ~observable() = default;
};
// our first observable with its own interface
class clock_observable
: public observable {
int m_time;
public:
clock_observable(int time)
: m_time(time){}
// we will use this later
static constexpr auto string_id() {
return "clock_observable";
}
std::string id() override {
return string_id();
}
void change_time() {
m_time++;
notifyObservers(); // notify observes of time change
}
int get_time() const {
return m_time;
}
};
// another observable
class account_observable
: public observable {
double m_balance;
public:
account_observable(double balance)
: m_balance(balance){}
// we will use this later
static constexpr auto string_id() {
return "account_observable";
}
std::string id() override {
return string_id();
}
void deposit_amount(double x) {
m_balance += x;
notifyObservers(); // notify observes of time change
}
int get_balance() const {
return m_balance;
}
};
class temperature_observable
: public observable {
double m_value;
public:
temperature_observable(double value)
: m_value(value){}
// we will use this later
static constexpr auto string_id() {
return "temperature_observable";
}
std::string id() override {
return string_id();
}
void increase_temperature(double x) {
m_value += x;
notifyObservers(); // notify observes of time change
}
int get_temperature() const {
return m_value;
}
};
Notice that each observer exposes an id function returning a string which identifies it. Now, let's assume we want to create an observer which monitors the clock and the account. We could have something like this:
class simple_observer_clock_account
: public observer {
std::unordered_map<std::string, void (simple_observer_clock_account::*) (observable&)> m_map;
void notify_impl(clock_observable& x) {
std::cout << "observer says time is " << x.get_time() << std::endl;
}
void notify_impl(account_observable& x) {
std::cout << "observer says balance is " << x.get_balance() << std::endl;
}
// casts the observable into the concrete type and passes it to the notify_impl
template <class X>
void dispatcher_function(observable& x) {
auto& concrete = static_cast<X&>(x);
notify_impl(concrete);
}
public:
simple_observer_clock_account() {
m_map[clock_observable::string_id()] = &simple_observer_clock_account::dispatcher_function<clock_observable>;
m_map[account_observable::string_id()] = &simple_observer_clock_account::dispatcher_function<account_observable>;
}
void notify(observable& x) override {
auto f = m_map.at(x.id());
(this->*f)(x);
}
};
I am using an unoderded_map so that the correct dispatcher_function will be called depending on the id of the observable. Confirm that this works:
int main() {
auto clock = new clock_observable(100);
auto account = new account_observable(100.0);
auto obs1 = new simple_observer_clock_account();
clock->registerObserver(obs1);
account->registerObserver(obs1);
clock->change_time();
account->deposit_amount(10);
}
A nice thing about this implementation is that if you try to register the observer to a temperature_observable you will get a runtime exception (as the m_map will not contain the relevant temperature_observable id).
This works fine but if you try now to adjust this observer so that it can monitor temperature_observables, things get messy. You either have to go edit the simple_observer_clock_account (which goes against the closed for modification, open for extension principle), or create a new observer as follows:
class simple_observer_clock_account_temperature
: public observer {
std::unordered_map<std::string, void (simple_observer_clock_account_temperature::*) (observable&)> m_map;
// repetition
void notify_impl(clock_observable& x) {
std::cout << "observer1 says time is " << x.get_time() << std::endl;
}
// repetition
void notify_impl(account_observable& x) {
std::cout << "observer1 says balance is " << x.get_balance() << std::endl;
}
// genuine addition
void notify_impl(temperature_observable& x) {
std::cout << "observer1 says temperature is " << x.get_temperature() << std::endl;
}
// repetition
template <class X>
void dispatcher_function(observable& x) {
auto& concrete = static_cast<X&>(x);
notify_impl(concrete);
}
public:
// lots of repetition only to add an extra observable
simple_observer_clock_account_temperature() {
m_map[clock_observable::string_id()] = &simple_observer_clock_account_temperature::dispatcher_function<clock_observable>;
m_map[account_observable::string_id()] = &simple_observer_clock_account_temperature::dispatcher_function<account_observable>;
m_map[temperature_observable::string_id()] = &simple_observer_clock_account_temperature::dispatcher_function<temperature_observable>;
}
void notify(observable& x) override {
auto f = m_map.at(x.id());
(this->*f)(x);
}
};
This works but it is a hell of a lot repetitive for just adding one additional observable. You can also imagine what would happen if you wanted to create any combination (ie account + temperature observable, clock + temp observable, etc). It does not scale at all.
The TMP solution essentially provides a way to do all the above automatically and re-using the overriden implementations as opposed to replicating them again and again. Here is how it works:
We want to build a class hierarchy where the base class will expose a number of virtual notify_impl(T&) method, one for each T concrete observable type that we want to observe. This is achieved as follows:
template <class Observable>
class interface_unit {
public:
virtual void notify_impl(Observable&) = 0;
};
// combined_interface<T1, T2, T3> would result in a class with the following members:
// notify_impl(T1&)
// notify_impl(T2&)
// notify_impl(T3&)
template <class... Observable>
class combined_interface
: public interface_unit<Observable>...{
using self_type = combined_interface<Observable...>;
using dispatcher_type = void (self_type::*)(observable&);
std::unordered_map<std::string, dispatcher_type> m_map;
public:
void map_register(std::string s, dispatcher_type dispatcher) {
m_map[s] = dispatcher;
}
auto get_dispatcher(std::string s) {
return m_map.at(s);
}
template <class X>
void notify_impl(observable& x) {
interface_unit<X>& unit = *this;
// transform the observable to the concrete type and pass to the relevant interface_unit.
unit.notify_impl(static_cast<X&>(x));
}
};
The combined_interface class inherits from each interface_unit and also allows us to register functions to the map, similarly to what we did earlier for the simple_observer_clock_account. Now we need to create a recursive hierarchy where at each step of the recursion we override notify_impl(T&) for each T we are interested in.
// forward declaration
// Iface will be combined_interface<T1, T2>
// The purpose of this class is to implement the virtual methods found in the Iface class, ie notify_impl(T1&), notify_impl(T2&)
// Each ImplUnit provides an override for a single notify_impl(T&)
// Root is the base class of the hierarchy; this will be the data (if any) held by the observer
template <class Root, class Iface, template <class, class> class... ImplUnits>
struct hierarchy;
// recursive
template <class Root, class Iface, template <class, class> class ImplUnit, template <class, class> class... ImplUnits>
struct hierarchy<Root, Iface, ImplUnit, ImplUnits...>
: public ImplUnit< hierarchy<Root, Iface, ImplUnits...>, Root > {
using self_type = hierarchy<Root, Iface, ImplUnit, ImplUnits...>;
using base_type = ImplUnit< hierarchy<Root, Iface, ImplUnits...>, Root >;
public:
template <class... Args>
hierarchy(Args&&... args)
: base_type{std::forward<Args>(args)...} {
using observable_type = typename base_type::observable_type;
Iface::map_register(observable_type::string_id(), &Iface::template notify_impl<observable_type>);
}
};
// specialise if we have iterated through all ImplUnits
template <class Root, class Iface>
struct hierarchy<Root, Iface>
: public Root
, public observer
, public Iface {
public:
template <class... Args>
hierarchy(Args&&... args)
: Root(std::forward<Args>(args)...)
, Iface(){}
};
At each step of the recursion, we register the dispatcher_function to our map.
Finally, we create a class which will be used for our observers:
template <class Root, class Iface, template <class, class> class... ImplUnits>
class observer_base
: public hierarchy<Root, Iface, ImplUnits...> {
public:
using base_type = hierarchy<Root, Iface, ImplUnits...>;
void notify(observable& x) override {
auto f = this->get_dispatcher(x.id());
return (this->*f)(x);
}
template <class... Args>
observer_base(Args&&... args)
: base_type(std::forward<Args>(args)...) {}
};
Let's now create some observables. For simplicity, I assume that the observer has not data:
class observer1_data {};
// this is the ImplUnit for notify_impl(clock_observable&)
// all such implementations must inherit from the Super argument and expose the observable_type type member
template <class Super, class ObserverData>
class clock_impl
: public Super {
public:
using Super::Super;
using observable_type = clock_observable;
void notify_impl(clock_observable& x) override {
std::cout << "observer says time is " << x.get_time() << std::endl;
}
};
template <class Super, class ObserverdData>
class account_impl
: public Super {
public:
using Super::Super;
using observable_type = account_observable;
void notify_impl(account_observable& x) override {
std::cout << "observer says balance is " << x.get_balance() << std::endl;
}
};
template <class Super, class ObserverdData>
class temperature_impl
: public Super {
public:
using Super::Super;
using observable_type = temperature_observable;
void notify_impl(temperature_observable& x) override {
std::cout << "observer says temperature is " << x.get_temperature() << std::endl;
}
};
Now we can easily create any observer we want, no matter what combinations we want to use:
using observer_clock = observer_base<observer1_data,
combined_interface<clock_observable>,
clock_impl>;
using observer_clock_account = observer_base<observer1_data,
combined_interface<clock_observable, account_observable>,
clock_impl, account_impl>;
using observer_clock_account_temperature = observer_base<observer1_data,
combined_interface<clock_observable, account_observable, temperature_observable>,
clock_impl, account_impl, temperature_impl>;
int main() {
auto clock = new clock_observable(100);
auto account = new account_observable(100.0);
auto temp = new temperature_observable(36.6);
auto obs1 = new observer_clock_account_temperature();
clock->registerObserver(obs1);
account->registerObserver(obs1);
temp->registerObserver(obs1);
clock->change_time();
account->deposit_amount(10);
temp->increase_temperature(2);
}
I can appreciate there is a lot to digest. Anyway, I hope it is helpful. If you want to understand in detail the TMP ideas above have a look at the Modern C++ design by Alexandrescu. One of the best I've read.
Let me know if anything is not clear and I will edit the answer.
If the number of sensor types is more or less stable (and it is - the changes are pretty rare in most cases) - then just be prepared on Observer side to get several kind of notifications:
class Observer
{
public:
virtual void notify(SenseNode& node) {
// implement here general actions - like printing: not interested in this
}
virtual void notify(RealTimeClock& node) {
notify(static_cast<SenseNode&>(node));
// by default go to more general function
}
// and follow this pattern - for all nodes you want to handle
// add corresponding notify(T&) function
};
When it happens you have to add new node type - then just add new virtual function to your base Observer class.
To implement this mechanism on Observable side - use double dispatch pattern:
class SenseNode {
public:
virtual void notifyObserver(Observer& observer) {
observer.notify(*this);
}
};
class RealTimeClock : public virtual SenseNode {
public:
virtual void notifyObserver(Observer& observer) {
observer.notify(*this);
// this will select proper Observer::notify(RealTimeClock&)
// because *this is RealTimeCLock
}
};
class SenseObservable: public SenseStateNode
{
public:
virtual void notifyObservers() {
for (auto& observer : observers)
notifyObserver(observer);
}
};
How it works in practice, see live demo
Here is my take. If I understand correctly, each observer knows what concrete observable is monitoring; the problem is that the observer only gets a base class pointer to the concrete observable and hence cannot access the full interface. Assuming you can use static_cast as previous answers have assumed, my idea is to create an additional class which will be responsible for casting the base class pointer to the concrete one, thus giving you access to the concrete interface. The code below uses different names than the ones in your post, but it illustrates the idea:
#include <vector>
#include <algorithm>
#include <iostream>
class observable;
class observer {
public:
virtual void notify(observable&) = 0;
};
// For simplicity, I will give some default implementation for storing the observers
class observable {
// assumping plain pointers
// leaving it to you to take of memory
std::vector<observer*> m_observers;
public:
observable() = default;
void notifyObservers() {
for(auto& obs : m_observers) obs->notify(*this);
}
void registerObserver(observer* x) {
m_observers.push_back(x);
}
void unregisterObserver(observer* x) {
// give your implementation here
}
virtual ~observable() = default;
};
// our first observable with its own interface
class clock_observable
: public observable {
int m_time;
public:
clock_observable(int time)
: m_time(time){}
void change_time() {
m_time++;
notifyObservers(); // notify observes of time change
}
int get_time() const {
return m_time;
}
};
// another observable
class account_observable
: public observable {
double m_balance;
public:
account_observable(double balance)
: m_balance(balance){}
void deposit_amount(double x) {
m_balance += x;
notifyObservers(); // notify observes of time change
}
int get_balance() const {
return m_balance;
}
};
// this wrapper will be inherited and allows you to access the interface of the concrete observable
// all concrete observers should inherit from this class
template <class Observable>
class observer_wrapper
: public observer {
virtual void notify_impl(Observable& x) = 0;
public:
void notify(observable& x) {
notify_impl(static_cast<Observable&>(x));
}
};
// our first clock_observer
class clock_observer1
: public observer_wrapper<clock_observable> {
void notify_impl(clock_observable& x) override {
std::cout << "clock_observer1 says time is " << x.get_time() << std::endl;
}
};
// our second clock_observer
class clock_observer2
: public observer_wrapper<clock_observable> {
void notify_impl(clock_observable& x) override {
std::cout << "clock_observer2 says time is " << x.get_time() << std::endl;
}
};
// our first account_observer
class account_observer1
: public observer_wrapper<account_observable> {
void notify_impl(account_observable& x) override {
std::cout << "account_observer1 says balance is " << x.get_balance() << std::endl;
}
};
// our second account_observer
class account_observer2
: public observer_wrapper<account_observable> {
void notify_impl(account_observable& x) override {
std::cout << "account_observer2 says balance is " << x.get_balance() << std::endl;
}
};
int main() {
auto clock = new clock_observable(100);
auto account = new account_observable(100.0);
observer* clock_obs1 = new clock_observer1();
observer* clock_obs2 = new clock_observer2();
observer* account_obs1 = new account_observer1();
observer* account_obs2 = new account_observer2();
clock->registerObserver(clock_obs1);
clock->registerObserver(clock_obs2);
account->registerObserver(account_obs1);
account->registerObserver(account_obs2);
clock->change_time();
account->deposit_amount(10);
}
As you can see, you do not need to cast every time you create a new observable; the wrapper class does this for you. One issue you may face is registering an observer to the wrong observable; in this case the static_cast would fail but you would get no compilation issues. One way around it is to have the observable expose a string that identifies it and have the observer check that string when it's registering itself. Hope it helps.
You could go with
class SenseStateNode
{
...
virtual ObservableValue& getValue(); //or pointer, comes with different tradeoffs
};
That way, each SenseObservable can return a type derived from ObservableValue. Then, you just have to come up with a usable, generic API for this observable value.
For example, it could be:
class SenseObservable
{
DateTime* asDateTime(); //returns NULL if not a date
float* asFloat(); //returns NULL if not a float
};
The trick is to come with a usable, extensible and generic API for the various observable values. Also, you hve to return them by pointer or reference to not slice them. Then, either the user or the owner has to manage memory.
It may not be the most elegant solution, but the following is an option: define an EventArgs structure that can hold any kind of data, then do a cast in EventHandlers. Here's a snippet I just wrote (not a native speaker of CPP though):
#include <iostream>
#include <map>
#include <vector>
using namespace std;
struct EventArgs;
typedef void (*EventHandler)(EventArgs args);
typedef std::vector<EventHandler> BunchOfHandlers;
typedef std::map<string, BunchOfHandlers> HandlersBySubject;
struct EventArgs
{
void* data;
EventArgs(void* data)
{
this->data = data;
}
};
class AppEvents
{
HandlersBySubject handlersBySubject;
public:
AppEvents()
{
}
void defineSubject(string subject)
{
handlersBySubject[subject] = BunchOfHandlers();
}
void on(string subject, EventHandler handler)
{
handlersBySubject[subject].push_back(handler);
}
void trigger(string subject, EventArgs args)
{
BunchOfHandlers& handlers = handlersBySubject[subject];
for (const EventHandler& handler : handlers)
{
handler(args);
}
}
};
struct FooData
{
int x = 42;
string str = "Test";
};
struct BarData
{
long y = 123;
char c = 'x';
};
void foo_handler_a(EventArgs args)
{
FooData* data = (FooData*)args.data;
cout << "foo_handler_a: " << data->x << " " << data->str << endl;
}
void foo_handler_b(EventArgs args)
{
FooData* data = (FooData*)args.data;
cout << "foo_handler_b: " << data->x << " " << data->str << endl;
}
void bar_handler_a(EventArgs args)
{
BarData* data = (BarData*)args.data;
cout << "bar_handler_a: " << data->y << " " << data->c << endl;
}
void bar_handler_b(EventArgs args)
{
BarData* data = (BarData*)args.data;
cout << "bar_handler_b: " << data->y << " " << data->c << endl;
}
int main()
{
AppEvents* events = new AppEvents();
events->defineSubject("foo");
events->defineSubject("bar");
events->on("foo", foo_handler_a);
events->on("foo", foo_handler_a);
events->on("bar", bar_handler_b);
events->on("bar", bar_handler_b);
events->trigger("foo", EventArgs(new FooData()));
events->trigger("bar", EventArgs(new BarData()));
return 0;
}
Inspired by Backbone events and the general Event Bus pattern.
Difficulty of Observer Pattern in C++ is to handle life-time and un-registration.
You might use the following:
class Observer;
class IObserverNotifier
{
public:
virtual ~IObserverNotifier() = default;
virtual void UnRegister(Observer&) = 0;
};
class Observer
{
public:
explicit Observer() = default;
virtual ~Observer() {
for (auto* abstractObserverNotifier : mAbstractObserverNotifiers)
abstractObserverNotifier->UnRegister(*this);
}
Observer(const Observer&) = delete;
Observer(Observer&&) = delete;
Observer& operator=(const Observer&) = delete;
Observer& operator=(Observer&&) = delete;
void AddObserverNotifier(IObserverNotifier& observerNotifier)
{
mAbstractObserverNotifiers.insert(&observerNotifier);
}
void RemoveObserverNotifier(IObserverNotifier& observerNotifier)
{
mAbstractObserverNotifiers.erase(&observerNotifier);
}
private:
std::set<IObserverNotifier*> mAbstractObserverNotifiers;
};
template<typename ... Params>
class ObserverNotifier : private IObserverNotifier
{
public:
ObserverNotifier() = default;
~ObserverNotifier() {
for (const auto& p : mObserverCallbacks) {
p.first->RemoveObserverNotifier(*this);
}
}
ObserverNotifier(const ObserverNotifier&) = delete;
ObserverNotifier(ObserverNotifier&&) = delete;
ObserverNotifier& operator=(const ObserverNotifier&) = delete;
ObserverNotifier& operator=(ObserverNotifier&&) = delete;
void Register(Observer& observer, std::function<void(Params...)> f) {
mObserverCallbacks.emplace_back(&observer, f);
observer.AddObserverNotifier(*this);
}
void NotifyObservers(Params... args) const
{
for (const auto& p : mObserverCallbacks)
{
const auto& callback = p.second;
callback(args...);
}
}
void UnRegister(Observer& observer) override
{
mObserverCallbacks.erase(std::remove_if(mObserverCallbacks.begin(),
mObserverCallbacks.end(),
[&](const auto& p) { return p.first == &observer;}),
mObserverCallbacks.end());
}
private:
std::vector<std::pair<Observer*, std::function<void(Params...)>>> mObserverCallbacks;
};
And then usage would be something like:
class Sensor
{
public:
void ChangeTime() {
++mTime;
mOnTimeChange.NotifyObservers(mTime);
}
void ChangeTemperature(double delta) {
mTemperature += delta;
mOnTemperatureChange.NotifyObservers(mTemperature);
}
void RegisterTimeChange(Observer& observer, std::function<void(double)> f) { mOnTimeChange.Register(observer, f); }
void RegisterTemperatureChange(Observer& observer, std::function<void(double)> f) { mOnTemperatureChange.Register(observer, f); }
private:
ObserverNotifier<int> mOnTimeChange;
ObserverNotifier<double> mOnTemperatureChange;
int mTime = 0;
double mTemperature = 0;
};
class Ice : public Observer {
public:
void OnTimeChanged(int time) {
mVolume -= mLose;
mOnVolumeChange.NotifyObservers(mVolume);
}
void OnTemperatureChanged(double t) {
if (t <= 0) {
mLose = 0;
} else if (t < 15) {
mLose = 5;
} else {
mLose = 21;
}
}
void RegisterVolumeChange(Observer& observer, std::function<void(double)> f) { mOnVolumeChange.Register(observer, f); }
private:
ObserverNotifier<double> mOnVolumeChange;
double mVolume = 42;
double mLose = 0;
};
class MyObserver : public Observer {
public:
static void OnTimeChange(int t) {
std::cout << "observer says time is " << t << std::endl;
}
static void OnTemperatureChange(double temperature) {
std::cout << "observer says temperature is " << temperature << std::endl;
}
static void OnIceChange(double volume) {
std::cout << "observer says Ice volume is " << volume << std::endl;
}
};
And test it:
int main()
{
Sensor sensor;
Ice ice;
MyObserver observer;
sensor.RegisterTimeChange(observer, &MyObserver::OnTimeChange);
sensor.RegisterTemperatureChange(observer, &MyObserver::OnTemperatureChange);
ice.RegisterVolumeChange(observer, &MyObserver::OnIceChange);
sensor.RegisterTimeChange(ice, [&](int t){ice.OnTimeChanged(t);});
sensor.RegisterTemperatureChange(ice, [&](double t){ice.OnTemperatureChanged(t);});
sensor.ChangeTemperature(0);
sensor.ChangeTime();
sensor.ChangeTemperature(10.3);
sensor.ChangeTime();
sensor.ChangeTime();
sensor.ChangeTemperature(42.1);
sensor.ChangeTime();
}
Demo

Simulate constructor behaviour for virtual methods

I am currently working on a small private project using C++ i came up with the following structure:
#include <iostream>
class A
{
std::vector<int> vec;
protected:
virtual bool onAdd(int toAdd) {
// should the 'adding' be suppressed?
// do some A specific checks
std::cout << "A::onAdd()" << std::endl;
return false;
}
public:
void add(int i) {
if(!onAdd(i)) {
// actual logic
vec.push_back(i);
}
}
};
class B : public A
{
protected:
bool onAdd(int toAdd) override {
// do some B specific checks
std::cout << "B::onAdd()" << std::endl;
return false;
}
};
In this example onAdd is basically meant to be a callback for add, but in a more polymorphic way.
The actual problem arises when a class C inherits from B and wants to override onAdd too. In this case the implementation in B will get discarded (i.e. not called) when calling C::add. So basically what I would like to achieve is a constructor-like behaviour where I am able to override the same method in different positions in the class hierarchy and all of those getting called.
My question now is: Is there a possibility/design to achieve this? I am sure that it wouldn't be as easy as cascading constructors, though.
Note: Don't focus too much on the add example. The question is about the callback like structure and not if it makes sense with an add.
I would just call my parents onAdd()
bool C::onAdd(int toAdd) {return my_answer && B::onAdd(toAdd);}
This can be a little confusing if you're expecting other developers to inherit from your base class. But for small private hierarchies it works perfectly.
I sometimes include a using statement to make this more explicit
class C : public B
{
using parent=B;
bool onAdd(int toAdd) override {return my_answer && parent::onAdd(toAdd);}
};
struct RunAndDiscard {
template<class Sig, class...Args>
void operator()(Sig*const* start, Sig*const* finish, Args&&...args)const{
if (start==finish) return;
for (auto* i = start; i != (finish-1); ++i) {
(*i)(args...);
}
(*(finish-1))(std::forward<Args>(args)...);
}
};
template<class Sig, class Combine=RunAndDiscard>
struct invokers {
std::vector<Sig*> targets;
template<class...Args>
decltype(auto) operator()(Args&&...args)const {
return Combine{}( targets.data(), targets.data()+targets.size(), std::forward<Args>(args)... );
}
};
struct AndTogetherResultWithShortCircuit {
template<class Sig, class...Args>
bool operator()(Sig*const* start, Sig*const* finish, Args&&...args)const{
if (start==finish) return true;
for (auto* i = start; i != (finish-1); ++i) {
if (!(*i)(args...)) return false;
}
return (*(finish-1))(std::forward<Args>(args)...);
}
};
This creates a per-instance table of things to do onAdd.
Creating a per-class table is harder; you need to chain your table with your parent type's table, which requires per-class boilerplate.
There is no way to get the C++ compiler to write either the per-instance version, or the per-class version, without doing it yourself.
There are C++20 proposals involving reflection and reification, plus the metaclass proposal, which may involve automating writing code like this (on both a per-instance and per-class basis).
Here is a live example of this technique being tested:
struct AndTogetherResultWithShortCircuit {
template<class Sig, class...Args>
bool operator()(Sig*const* start, Sig*const* finish, Args&&...args)const{
if (start==finish) return true;
for (auto* i = start; i != (finish-1); ++i) {
if (!(*i)(args...)) return false;
}
return (*(finish-1))(std::forward<Args>(args)...);
}
};
class A {
std::vector<int> vec;
protected:
invokers<bool(A*, int), AndTogetherResultWithShortCircuit> onAdd;
public:
void add(int i) {
if (!onAdd(this, i)) {
vec.push_back(i);
}
}
};
class B : public A
{
public:
B() {
onAdd.targets.push_back([](A* self, int x)->bool{
// do some B specific checks
std::cout << "B::onAdd(" << x << ")" << std::endl;
return x%2;
});
}
};
class C : public B
{
public:
C() {
onAdd.targets.push_back([](A* self, int x)->bool{
// do some B specific checks
std::cout << "C::onAdd(" << x << ")" << std::endl;
return false;
});
}
};
When you want to write your own OO-system, you can in C++, but C++ doesn't write it for you.
If you want a generic solution perhaps you could use CRTP with variadic templates instead of runtime polymophism.
Taking inspiration from this answer and this answer:
template<class... OnAdders> class A : private OnAdders... {
std::vector<int> vec;
template<class OnAdder>
bool onAdd(int toAdd){
return static_cast<OnAdder*>(this)->onAdd(toAdd);
}
template<typename FirstOnAdder, typename SecondOnAdder, class... RestOnAdders>
bool onAdd(int toAdd){
if (onAdd<FirstOnAdder>(toAdd))
return true;
return onAdd<SecondOnAdder, RestOnAdders...>(toAdd);
}
public:
void add(int i) {
if (onAdd<OnAdders...>(i))
return;
// actual logic
vec.push_back(i);
}
};
class B {
public:
bool onAdd(int toAdd) {
// do some B specific checks
std::cout << "B::onAdd()" << std::endl;
return false;
}
};
Which you could use like:
A<B,C> a;
a.add(42);
Live demo.
The following solution uses std::function to add each callback during each constructor:
#include <iostream>
#include <vector>
#include <functional>
class A
{
std::vector<int> vec;
protected:
bool onAdd(int toAdd)
{
// do some A specific checks
std::cout << "A::onAdd()" << std::endl;
return true;
}
// vector of callback functions. Initialized with A::onAdd() callback as the first entry
std::vector<std::function<bool(int)>> callbacks{{[this](int toAdd){return onAdd(toAdd); }}};
public:
void add(int i)
{
for(auto& callback : callbacks) {
if(!callback(i))
return;
}
// actual logic
vec.push_back(i);
}
};
class B : public A
{
public:
B()
{
callbacks.emplace_back([this](int toAdd){return onAdd(toAdd); });
}
protected:
bool onAdd(int toAdd)
{
// do some B specific checks
std::cout << "B::onAdd()" << std::endl;
return true;
}
};
class C : public B
{
public:
C()
{
callbacks.emplace_back([this](int toAdd){return onAdd(toAdd); });
}
protected:
bool onAdd(int toAdd)
{
// do some C specific checks
std::cout << "C::onAdd()" << std::endl;
// must also call B::onAdd()
return true;
}
};
int main()
{
C c;
c.add(5);
}
Prints:
A::onAdd()
B::onAdd()
C::onAdd()