How to mark which class to cast to in c++? - 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;
}

Related

Which pattern to generify instantiation of objects that have different Ctor arguments

I would like to construct a robot with or without a tool, a mobile base, and other parts. As I want to automatize the configuration of the parts, I have a class Robot with the parts as template arguments
For instance, in the code below, the code will build as long as we use tools that have the same constructor signature as ToolInterface. It does build with a Screwdriver but does not with a Gripper.
#include <iostream>
#include <string>
class BaseRobot
{
public:
BaseRobot(){};
};
class ToolInterface
{
public:
ToolInterface(BaseRobot* _base, std::string _name):name{_name}{/*register _base*/};
std::string name;
bool param_1;
char param_2;
};
template<class T, class... Args>
constexpr T* construct(Args... args)
{
if constexpr (std::is_same<T, nullptr_t>::value)
{
return nullptr;
}
else
{
return new T(args...);
}
};
template<class Tool>
class Robot : public BaseRobot
{
protected:
Tool* tool;
public:
Robot():tool(construct<Tool>(this, "tool")){ // <--- here is my problem !!
if constexpr (! std::is_same<Tool, nullptr_t>::value)
{
//do stuff on/with tool->param_1, tool->param_2, ...
std::cout << "tool configured" << std::endl;
}
else
std::cout << "no tool" << std::endl;
};
};
class Screwdriver: public ToolInterface
{
public:
Screwdriver(BaseRobot* _base, std::string _name):ToolInterface(_base, _name){};
};
class Gripper: public ToolInterface
{
public:
Gripper(BaseRobot* _base, std::string _name, bool _reversed):
ToolInterface(_base, _name)
,reversed{_reversed}{};
bool reversed;
};
int main()
{
Robot<Screwdriver> robot_screwdriver;
Robot<nullptr_t> robot_null;
//Robot<Gripper> robot_gripper; //does not build
return 0;
}
Here are some ideas :
using a ToolConfig struct that is passed as an argument of Tools. If a tool requires more arguments, one should subclass ToolConfig and cast it into the tool constructor (see below): damn, that looks cumbersome and ugly!
enforce inherited ToolInterface classes Ctor signature: some tools must have a different Ctor signature
using a variadic template to pass args into the template: not reasonable because, in the end, I want something like template<class Tool1, class Tool2, class MobileBase, class Camera> class Robot
solution 1 would look like
struct ToolConfig
{
std::string name;
};
struct GripperConfig : public ToolConfig
{
bool reversed;
};
class Gripper : public ToolInterface
{
public:
Gripper(ToolConfig& _config):
ToolInterface(_config)
,reversed{static_cast<GripperConfig&>(_config).reversed}{};
bool reversed;
};
Do you have a magic pattern to solve my problem? Is my pattern wrong?
You could also use tuple instead of struct, not ideal but this works as well:
#include <iostream>
#include <string>
#include <tuple>
class BaseRobot
{
public:
BaseRobot() {};
};
class ToolInterface
{
public:
ToolInterface(std::string _name) :name{ _name } {/*register _base*/ };
std::string name;
bool param_1;
char param_2;
};
template <typename T, typename ... Types, std::size_t ... Indices>
constexpr T* apply_impl(const std::tuple<Types...>& tuple, std::index_sequence<Indices...>)
{
return new T(std::get<Indices>(tuple)...);
}
template <typename T, typename ... Types>
constexpr T* apply(const std::tuple<Types...>& tuple)
{
return apply_impl<T>(tuple, std::index_sequence_for<Types...>());
}
template<class T, class... Args>
constexpr T* construct(std::tuple<Args...> args)
{
if constexpr (std::is_same<T, nullptr_t>::value)
{
return nullptr;
}
else
{
return apply<T>(args);
}
}
template<class Tool>
class Robot : public BaseRobot
{
protected:
Tool* tool;
public:
template<class ...Args1> //, class ...Args2>
Robot(std::tuple<Args1...> p1): // , std::tuple<Args2...> p2):
tool(construct<Tool>(p1))
{ // <--- here is my problem !!
if constexpr (!std::is_same<Tool, nullptr_t>::value)
{
//do stuff on/with tool->param_1, tool->param_2, ...
std::cout << "tool configured" << std::endl;
}
else
std::cout << "no tool" << std::endl;
};
};
class Screwdriver : public ToolInterface
{
public:
Screwdriver(std::string _name) :ToolInterface(_name) {};
};
class Gripper : public ToolInterface
{
public:
Gripper(std::string _name, bool _reversed) :
ToolInterface(_name)
, reversed{ _reversed }{};
bool reversed;
};
int main()
{
using p1 = std::tuple<std::string>;
Robot<Screwdriver> robot_screwdriver(p1{"sdvr"});
return 0;
}
Could be improved I agree.
You could pass factory lambdas that generate your tools in the initializer.
template<typename Func>
Robot(Func f):tool(f(this, "tool")){ // <--- here is my problem !!
if constexpr (! std::is_same<Tool, std::nullptr_t>::value)
{
//do stuff on/with tool->param_1, tool->param_2, ...
std::cout << "tool configured" << std::endl;
}
else
std::cout << "no tool" << std::endl;
};
The call site would look like this:
Robot<Screwdriver> robot_screwdriver([](auto... args){ return new Screwdriver(args...); });
Robot<std::nullptr_t> robot_null([](auto...){ return nullptr; });
Robot<Gripper> robot_gripper([](auto... args){ return new Gripper(args..., true); });
Not exactly beautiful, but it works.
See here for a full example. Does this solve your problem?
If you can use c++17, you can add a class template deduction guide to reduce some of the redundancy at the call site.

How can you iterate over elements of a std::tuple with a shared base class?

Assume you have a std::tuple with a common base class:
class MyBase { public: virtual int getVal() = 0; };
class MyFoo1: public MyBase { public: int getVal() override { return 101; } };
class MyFoo2: public MyBase { public: int getVal() override { return 202; } };
using MyTuple = std::tuple<MyFoo1, MyFoo2, MyFoo1>;
How do you iterate over the elements of the tuple at runtime? The usual answer is that you can't because they all have different types, but here I'm happy for a static type of MyBase*. I'm hoping for code like this:
MyTuple t;
for (Base* b : iterate_tuple<MyBase>(t)) {
std::cout << "Got " << b->getVal() << "\n";
}
There are a lot of helpful ideas over at How can you iterate over the elements of an std::tuple?, but they all include the code to run at each iteration in the fiddly template code, whereas I'd like all the fiddly template code bundled into the hypothetical iterate_tuple function so my code is just a normal for loop.
Here's a little wrapper function that gets the tuple value by index, specified at runtime, which does a linear search for the right index by recursively calling itself with a different template parameter. You specify its return type as a template parameter, and the value gets implicitly converted to it.
template <class BaseT, class TupleT, size_t currentIndex = 0>
BaseT* getBasePtr(TupleT& t, size_t desiredIndex) {
if constexpr (currentIndex >= std::tuple_size<TupleT>::value) {
return nullptr;
}
else {
if (desiredIndex == currentIndex) {
return &std::get<currentIndex>(t);
}
else {
return getBasePtr<BaseT, TupleT, currentIndex + 1>(t, desiredIndex);
}
}
}
You can then use it in a loop over the indices of the tuple:
for (size_t i = 0; i < std::tuple_size<MyTuple>::value; ++i) {
MyBase* b = getBasePtr<MyBase>(t, i);
std::cout << "At " << i << " got " << b->getVal() << "\n";
}
It's not quite as neat as a range-based for loop but it's still pretty straightforward to use. (You could wrap it in an iterator class that would support range-based loops but I don't really think it's worth the effort.)
As mentioned and suggested in the question linked to using std::apply is a good way to get each individual element of the tuple.
Making a small helper function to wrap the forwarding of each tuple element makes it easy to use.
It's not the specific for-loop syntax you asked for, but it's as easy to follow if you ask me.
#include <tuple>
#include <utility>
#include <iostream>
class MyBase { public: virtual int getVal() = 0; };
class MyFoo1: public MyBase { public: int getVal() override { return 101; } };
class MyFoo2: public MyBase { public: int getVal() override { return 202; } };
using MyTuple = std::tuple<MyFoo1, MyFoo2, MyFoo1>;
template <typename Tuple, typename Callable>
void iterate_tuple(Tuple&& t, Callable c) {
std::apply([&](auto&&... args){ (c(args), ...); }, t);
}
int main() {
MyTuple t;
iterate_tuple(t, [](auto& arg) {
std::cout << "Got " << arg.getVal() << "\n";
});
iterate_tuple(t, [](MyBase& arg) {
std::cout << "Got " << arg.getVal() << "\n";
});
}
We can get the exact type by using auto or use the common base type.
As Sam suggests in the comments, it's quite simple to create an array from a tuple.
template<typename Base, typename Tuple, size_t... Is>
std::array<Base *, std::tuple_size_v<Tuple>> iterate_tuple_impl(Tuple& tuple, std::index_sequence<Is...>)
{
return { std::addressof(std::get<Is>(tuple))... };
}
template<typename Base, typename Tuple>
std::array<Base *, std::tuple_size_v<Tuple>> iterate_tuple(Tuple& tuple)
{
return iterate_tuple_impl(tuple, std::make_index_sequence<std::tuple_size_v<Tuple>>{});
}
If you have inheritance, why not to do without tuple and use inheritance capabilities like this:
#include <iostream>
#include <vector>
class MyBase { public: virtual int getVal() = 0; };
class MyFoo1 : public MyBase { public: int getVal() override { return 101; } };
class MyFoo2 : public MyBase { public: int getVal() override { return 202; } };
int main() {
std::vector<std::unique_ptr<MyBase>> base;
base.emplace_back(new MyFoo1);
base.emplace_back(new MyFoo2);
for (auto && derived : base) {
std::cout << derived->getVal() << std::endl;
}
}
I would directly use std::apply, but you can create array of Base*:
template <typename Base, typename Tuple>
std::array<Base*, std::tuple_size<Tuple>> toPtrArray(Tuple& tuple)
{
return std::apply([](auto& ... args){ return std::array<Base*, std::tuple_size<Tuple>>{{&args}}; }, tuple);
}
And then
MyTuple t;
for (Base* b : toPtrArray<MyBase>(t)) {
std::cout << "Got " << b->getVal() << "\n";
}

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

How to handle casting in Heterogenous container

I am trying to implement Heterogenous container, using pointers to non-template base class. While the derived class is a template.
Note: Derived class types are known at compile time.
Note: the container size is fixed.
First attempt: is using a helper array to hold integer representation of the correct type. Its size equal to the container size. Yet I ended up with many if statements.
my problem is slightly similar to this thread yet I don't know to how to use std::type_index.
I am trying to avoid solving this using Boost::variant and run-time polymorphism.
My question: is there better way to handle casting from the base class to the derived class ?
Edit1 in my actual problem. the template class has 16 different types.
example:
template<typename Color, typename Smell, typename Shape, typename Origin>
class Fruit{};
Implementation:
class Plant
{ public: std::string sound = "I am jst a plant";};
template <typename T>
class Fruit : public Plant
{public: std::string sound = "I am jst a Fruit!";};
// list of types known at compile time.
struct Apple{ }; // types = 0
struct Orange{ }; // types = 1
struct Banana{ }; // types = 2
template <>
class Fruit<Apple> : public Plant
{public: std::string sound = "I am Apple";};
template <>
class Fruit<Orange> : public Plant
{public: std::string sound = "I am Orange";};
template <>
class Fruit<Banana> : public Plant
{public: std::string sound = "I am Banana";};
template <typename T>
void MakeSound(T fruit)
{
std::cout << fruit->sound << std::endl;
}
int main() {
Plant* Basket[5] = {nullptr};
int types[5] = {0};
Basket[0] = new Fruit<Apple>;
types[0] = 0;
Basket[1] = new Fruit<Orange>;
types[1] = 1;
Basket[2] = new Fruit<Orange>;
types[2] = 1;
Basket[3] = new Fruit<Apple>;
types[3] = 0;
Basket[4] = new Fruit<Apple>;
types[4] = 0;
for (int i = 0; i < 5; ++i)
{
if (types[i] == 0)
{
MakeSound(static_cast<Fruit<Apple> *>(Basket[i]));
}
else if (types[i] == 1)
{
MakeSound(static_cast<Fruit<Orange> *>(Basket[i]));
}
else
{
MakeSound(static_cast<Fruit<Banana> *>(Basket[i]));
}
}
}
I suggest the use of a virtual function to detect id of the type of the derived object; id of the type that I suggest registered in the template class parameter (as the sound) to avoid the need of specializations fo Fruits.
And please: you tagged C++11; so use smart pointers.
An example of what I mean
#include <string>
#include <vector>
#include <memory>
#include <iostream>
struct Plant
{ virtual std::size_t getTypeId () = 0; };
struct Apple
{
static constexpr size_t typeId { 0U };
static std::string const & getSnd ()
{ static std::string sound { "I am Apple" }; return sound; }
};
struct Orange
{
static constexpr size_t typeId { 1U };
static std::string const & getSnd ()
{ static std::string sound { "I am Orange" }; return sound; }
};
struct Banana
{
static constexpr size_t typeId { 2U };
static std::string const & getSnd ()
{ static std::string sound { "I am Banana" }; return sound; }
};
template <typename T>
struct Fruit : public Plant
{
virtual std::size_t getTypeId () override { return T::typeId; }
static std::string const & getSnd () { return T::getSnd(); }
};
template <typename T>
void MakeSound(T fruit)
{ std::cout << fruit->getSnd() << std::endl; }
int main()
{
std::vector<std::unique_ptr<Plant>> bask;
bask.emplace_back(new Fruit<Apple>);
bask.emplace_back(new Fruit<Orange>);
bask.emplace_back(new Fruit<Orange>);
bask.emplace_back(new Fruit<Apple>);
bask.emplace_back(new Fruit<Apple>);
bask.emplace_back(new Fruit<Banana>);
for ( auto const & up : bask)
{
switch ( up->getTypeId() )
{
case 0U:
MakeSound(static_cast<Fruit<Apple> *>(up.get()));
break;
case 1U:
MakeSound(static_cast<Fruit<Orange> *>(up.get()));
break;
case 2U:
MakeSound(static_cast<Fruit<Banana> *>(up.get()));
break;
default:
break;
}
}
}

Defining Visitors Inline in Modern C++ alternate take

I found a very interesting article on
Defining Visitors Inline in Modern C++
The solution proposed is quite complicated though.
I wonder if there is a simpler way of addressing this scenario?
code and example added below to avoid needing to follow link.
Taking the example from the paper, given the following classes:
struct Triangle;
struct Square;
struct PolygonVisitor
{
virtual ~PolygonVisitor() {}
virtual void visit(Triangle& tr) = 0;
virtual void visit(Square& sq) = 0;
};
struct Polygon
{
virtual void accept(PolygonVisitor& v) = 0;
};
struct Triangle : Polygon
{
void accept(PolygonVisitor& v) override
{
v.Visit(*this);
}
};
struct Square : Polygon
{
void accept(PolygonVisitor& v) override
{
v.Visit(*this);
}
};
An inline visitor is constructed and used to work out how many sides a
shape has:
int CountSides(Polygon& p)
{
int sides = 0;
auto v = begin_visitor<PolygonVisitor>()
.on<Triangle>([&sides](Triangle& tr)
{
sides = 3;
})
.on<Square>([&sides](Square& sq)
{
sides = 4;
})
.end_visitor();
p.Accept(v);
return sides;
}
The inline visitor is defined as follows (code taken from
https://github.com/jbcoe/inline_visitor):
template <typename T, typename F, typename BaseInnerVisitor, typename ArgsT>
class ComposeVisitor
{
public:
class InnerVisitor : public BaseInnerVisitor
{
public:
using BaseInnerVisitor::Visit;
typedef typename BaseInnerVisitor::VisitorInterface VisitorInterface;
InnerVisitor(ArgsT&& args)
: BaseInnerVisitor(std::move(args.second)), m_f(std::move(args.first))
{
}
void Visit(T& t) final
{
VisitImpl(t);
}
private:
template <typename F_ = F>
typename std::enable_if<
std::is_assignable<std::function<void(T&)>, F_>::value>::type
VisitImpl(T& t)
{
m_f(t);
}
template <typename F_ = F>
typename std::enable_if<std::is_assignable<
std::function<void(T&, VisitorInterface&)>, F_>::value>::type
VisitImpl(T& t)
{
m_f(t, *this);
}
F m_f;
};
ComposeVisitor(ArgsT&& args) : m_args(std::move(args))
{
}
template <typename Tadd, typename Fadd>
ComposeVisitor<Tadd, Fadd, InnerVisitor, std::pair<Fadd, ArgsT>>
on(Fadd&& f) &&
{
return ComposeVisitor<Tadd, Fadd, InnerVisitor, std::pair<Fadd, ArgsT>>(
std::make_pair(std::move(f), std::move(m_args)));
}
template <typename InnerVisitor_ = InnerVisitor>
typename std::enable_if<!std::is_abstract<InnerVisitor_>::value,
InnerVisitor>::type
end_visitor() &&
{
return InnerVisitor(std::move(m_args));
}
ArgsT m_args;
};
template <typename TVisitorBase>
class EmptyVisitor
{
public:
class InnerVisitor : public TVisitorBase
{
public:
using TVisitorBase::Visit;
typedef TVisitorBase VisitorInterface;
InnerVisitor(std::nullptr_t)
{
}
};
template <typename Tadd, typename Fadd>
ComposeVisitor<Tadd, Fadd, InnerVisitor, std::pair<Fadd, std::nullptr_t>>
on(Fadd&& f) &&
{
return ComposeVisitor<Tadd, Fadd, InnerVisitor,
std::pair<Fadd, std::nullptr_t>>(
std::make_pair(std::move(f), nullptr));
}
};
template <typename TVisitorBase>
EmptyVisitor<TVisitorBase> begin_visitor()
{
return EmptyVisitor<TVisitorBase>();
}
One possible way of tackling this problem is inheriting from the abstract visitor ( PolygonVisitor in the example) a new class (InlineVisitor) that takes in its constructor a std::function for each abstract method it has to implement.
Each abstract method is implemented it in term of the std::function stored
#include <functional>
#include <iostream>
struct Triangle;
struct Square;
struct PolygonVisitor
{
virtual ~PolygonVisitor() {}
virtual void visit(Triangle& tr) = 0;
virtual void visit(Square& sq) = 0;
};
struct Polygon {
virtual void accept(PolygonVisitor& v) = 0;
};
struct Triangle : Polygon
{
void accept(PolygonVisitor& v) override { v.visit(*this); }
};
struct Square : Polygon
{
void accept(PolygonVisitor& v) override { v.visit(*this); }
};
class InlineVisitor : public PolygonVisitor
{
public:
virtual void visit(Triangle& value) { triangleFx_(value); }
virtual void visit(Square& value) { squareFx_(value); }
std::function<void(Triangle&)> triangleFx_;
std::function<void(Square&)> squareFx_;
InlineVisitor(const std::function<void(Triangle&)> triangleFx,
const std::function<void(Square&)> squareFx)
: triangleFx_(triangleFx)
, squareFx_(squareFx) {}
};
int countSides(Polygon& p)
{
int sides = 0;
InlineVisitor countSidesVisitor([&sides](Triangle& tr) { sides = 3; },
[&sides](Square& sq) { sides = 4; });
p.accept(countSidesVisitor);
return sides;
}
int main(int argc, char *argv[])
{
Triangle t;
Square s;
std::cout << "sides of Triangle: " << countSides(t) << std::endl
<< "sides of Square: " << countSides(s) << std::endl;
return 0;
};
The original implementation is more general while this retains the basic idea but is a simpler