I am making a class called "StateMachine" to make other classes that inherit that logic.
Trying to make the "State" structure store a pointer to the function to execute in that state, I have found myself needing to use lambda functions. However, I can't seem to declare an auto member inside a struct without it being "scatic const".
statemachine.h
#include <vector>
#include <string>
#include <map>
using namespace std;
struct State
{
string id;
auto action;
string next;
State():id(""){}
State(string _id, auto func, string n = ""):id(_id), action(func), next(n){}
};
class StateMachine
{
protected:
void addState(string id, auto func)
{
if(activeState == ""){activeState = id;}
stateList.insert(pair<string, State>(id, State(id, func)));
}
void doAction()
{
if(stateList[activeState].action != nullptr)
{
(*stateList[activeState].action)();
if(stateList[activeState].next != "")
{
activeState = stateList[activeState].next;
}
}
}
void setState(string state)
{
if(stateList.count(state) != 0)
{
activeState = state;
}
}
string getState()
{
return activeState;
}
private:
map<string, State> stateList;
string activeState = "";
};
Example of use
class Player : public StateMachine
{
public:
Player()
{
addState("ST_SPAWN", [this]{this->OnSpawn();});
}
virtual ~Player(){}
void OnSpawn()
{
//...
}
};
The error
/home/yawin/Dokumentuak/Proyectos/C++/Dough/src/./include/interfaces/statemachine.h:34:10: error: non-static data member declared ‘auto’
auto action;
What can I do?
You could use std::function to simplify this.
#include <functional>
struct State {
string id;
std::function<void()> action;
string next;
State(){id = "";}
State(string _id, std::function<void()> func, string n = "") :
id(_id), action(func), next(n) {}
};
class StateMachine {
//...
void addState(string id, std::function<void()> func) {
if(activeState == "") activeState = id;
stateList.emplace(id, State{id, func});
}
//...
Related
My problem is very specific. I have the following requirement, I need to set member variables that exist in child class from parent class, for several reasons. My plan is to pass a function pointer of the setter method (which exist in child class), that takes string as argument, to the parent class at construction. The parent class defines a public method that takes member name and value string as argument and invokes the function pointer of the member with value string. The parent class can exist in a dll or lib and have no access to any conversion or factory methods, so the setter method have to be defined in child class.
Since the parent can be a base class for other classes, i wrote some macros shown as below:
#define DEFINE_VAL(Type, memberName) \
private: \
Type memberName; \
void set##memberName(std::string const& val) { \
memberName = convert_to_val(val); /* this will be a call to factory which converts string to value type*/\
/* or call to local implementation for conversion*/
}; \
#define INIT_VAL(memberName) \
{ memberName, \
[&](std::string const& val) { set##memberName(val); }}
Parent and child classes are as below:
// parent.h probably in dll
class parent
{
public:
parent(std::map<std::string, std::function<void(std::string const&)>>& m)
: m(m)
{ }
...
private:
std::map<std::string, std::function<void(std::string const&)>> m;
};
// child.h
class child : public parent
{
public:
child() : parent({ INIT_VAL(iVal), ... })
{ }
private:
DEFINE_VAL(int, iVal);
...
};
The child class can have many variables defined and its a bit annoying to first use DEFINE_VAL macro and then pass each variable's setter method with INIT_VAL macro. Can this be done in one macro (probably in DEFINE_VAL)? or any ideas on automatic registration of member name and function pointer to parent class?
I would also appreciate any alternative ideas on accomplishing my requirement.
I need to set member variables that exist in child class from parent class, for several reasons. My plan is to pass a function pointer of the setter method (which exist in child class), that takes string as argument, to the parent class at construction.
When parent class constructor is invoked the derived class and its members have not been initialized yet and, pedantically, they do not exist yet. For this reason, it is not possible to set derived class members from its base class constructor.
One solution is to use a virtual function to set members by name.
Without built-in reflection in current C++, to associate names with data members and generate member accessors the best practice is still to use macros. One of the best macros for this purpose is BOOST_HANA_DEFINE_STRUCT.
boost::lexical_cast<T> can be used to convert from std::string to any T.
A working example with deep and multiple inheritance support:
#include <boost/hana/define_struct.hpp>
#include <boost/hana/accessors.hpp>
#include <boost/hana/for_each.hpp>
#include <boost/hana/concat.hpp>
#include <boost/hana/length.hpp>
#include <boost/lexical_cast.hpp>
#include <unordered_map>
#include <functional>
#include <iostream>
namespace hana = boost::hana;
struct MemberSetter {
// Using void* to reduce the number of template instantiations.
using SetterFn = std::function<void(void*, std::string const&)>;
using Setters = std::unordered_map<std::string, SetterFn>;
Setters setters_;
template<class Derived, class Accessors>
MemberSetter(Derived* that, Accessors& accessors) {
hana::for_each(accessors, [this](auto const& pair) {
auto setter = [accessor = hana::second(pair)](void* vthat, std::string const& value) {
auto* that = static_cast<Derived*>(vthat);
auto& member = accessor(*that);
member = boost::lexical_cast<std::remove_reference_t<decltype(member)>>(value);
};
auto name = hana::first(pair);
setters_.emplace(std::string(hana::to<char const*>(name), hana::length(name)), std::move(setter));
});
}
bool findAndSetMember(void* that, std::string const& name, std::string const& value) const {
auto setter = setters_.find(name);
if(setter != setters_.end()) {
(setter->second)(that, value);
return true;
}
return false;
}
};
struct A {
virtual ~A() = default;
virtual bool setMember(std::string const& name, std::string const& value) = 0;
};
struct B : A {
BOOST_HANA_DEFINE_STRUCT(B,
(int, a),
(double, b)
);
bool setMember(std::string const& name, std::string const& value) override {
constexpr auto accessors = hana::accessors<B>();
static MemberSetter const setter(this, accessors);
return setter.findAndSetMember(this, name, value);
}
};
struct C : B {
BOOST_HANA_DEFINE_STRUCT(C,
(std::string, c)
);
bool setMember(std::string const& name, std::string const& value) override {
constexpr auto accessors = hana::concat(hana::accessors<B>(), hana::accessors<C>()); // Join with members of the base class.
static MemberSetter const setter(this, accessors);
return setter.findAndSetMember(this, name, value);
}
};
int main() {
C c;
c.setMember("a", "1");
c.setMember("b", "2.3");
c.setMember("c", "hello");
std::cout << c.a << ' ' << c.b << ' ' << c.c << '\n';
}
Output:
1 2.3 hello
Just use a virtual function to set it, and move the map to the child as it really should be an implementation detail. This way the parent class doesn't really have anything to do with how the members are set.
class parent
{
public:
virtual ~parent() = default;
protected:
virtual void do_set(const std::string& name, const std::string& value) = 0;
private:
void set(const std::string& name, const std::string& value) {
do_set(name, value);
// Do synchronization here
}
};
class child : public parent
{
protected:
void do_set(const std::string& name, const std::string& value) override {
child::setter_map.at(name)(*this, value);
}
private:
int iVal;
static const std::map<std::string, void(*)(child&, const std::string&)> setter_map;
};
#define INIT_VAL(NAME, ...) { #NAME, [](child& c, const std::string& value) __VA_ARGS__ }
const std::map<std::string, void(*)(child&, const std::string&)> child::setter_map = {
INIT_VAL(iVal, {
c.iVal = convert_to_val(value);
}),
// Init other members
};
And from this, you might be able to find a better way to implement set (Maybe a simple if (name == ...) ... else if (name == ...) ... would work)
Or if you don't want to use runtime polymorphism, at least don't store a map in every instance of parent. Store a reference to a global map (Which would be like a vtable itself):
class parent
{
public:
parent() = delete;
protected:
using setter_map = std::map<std::string, void(*)(parent&, const std::string&)>;
parent(const setter_map& child_smap) noexcept : smap(&child_smap) {};
private:
void set(const std::string& name, const std::string& value) {
smap->at(name)(*this, value);
// Do synchronization here
}
const setter_map* smap;
};
class child : public parent {
public:
child() : parent(smap) {};
private:
int iVal;
static const setter_map smap;
};
#define INIT_VAL(NAME, ...) { #NAME, \
[](parent& _c, const std::string& value) { \
child& c = static_cast<child&>(_c); \
__VA_ARGS__ \
} \
}
const child::setter_map child::smap = {
INIT_VAL(iVal, {
c.iVal = convert_to_val(value);
}),
// (Other member setters here)
};
#undef INIT_VAL
// Or having the setters inside the class, like in your original code
class child2 : public parent {
public:
child2() : parent(smap) {};
private:
int iVal;
void set_iVal(const std::string& value) {
iVal = convert_to_val(value);
}
// Using a macro (Probably don't need the macros here, writing out a setter is more clear)
template<class T>
using type = T;
#define DEFINE_VAL(TYPE, NAME, ...) \
void set_ ## NAME (const std::string& value) { \
__VA_ARGS__ \
} \
type<TYPE> NAME
DEFINE_VAL(float, fVal, {
fVal = convert_val_to_float(value);
});
DEFINE_VAL(char[2], charArrVal, {
charArrVal[0] = value[0];
charArrVal[1] = value[1];
});
static const setter_map smap;
};
#define INIT_VAL(NAME) { #NAME, [](parent& p, const std::string& value) { static_cast<child2&>(p).set_ ## NAME (value); } }
const child2::setter_map child2::smap = {
INIT_VAL(iVal), INIT_VAL(fVal), INIT_VAL(charArrVal)
};
#undef INIT_VAL
// Or if `convert_to_val(value)` is literally the body of every setter, that simplifies the `INIT_VAL` macro
class child3 : public parent {
public:
child3() : parent(smap) {};
private:
int iVal;
static const setter_map smap;
};
#define INIT_VAL(NAME) { #NAME, [](parent& p, const std::string& value) { static_cast<child3&>(p). NAME = convert_to_val(value); } }
const child3::setter_map child3::smap = {
INIT_VAL(iVal)
};
I have two classes and depending on the nature of key, I would like to get the struct value out of the boost::variant. The code is listed below.
#include <iostream>
#include <boost/variant.hpp>
using namespace std;
class A {
public:
struct greeting {
string hello;
};
class B {
public:
struct greeting {
string bye;
};
};
typedef boost::variant<A::greeting, B::greeting> greet;
greet getG(string key) {
greet g;
if (key == "A") {
g.hello = "MY ENEMY"; // this line doesn't work
}
else {
g.bye = "MY FRIEND"; // nor this line
}
return g;
};
int main() {
A a;
B b;
greet h = getG("A");
A::greeting my = boost::get<A::greeting>(h);
cout << my.hello << endl;
return 0;
}
The exact error that I am getting is:
error: no member named 'hello' in 'boost::variant<A::greeting, B::greeting, boost::detail::variant::void_, boost::detail::variant::void_, ...>' g.hello = "MY ENEMY"; and
error: no member named 'bye' in 'boost::variant<A::greeting, B::greeting, .../>' g.bye = "MY FRIEND";
Any help is appreciated.
The variant type doesn't have the .hello and .bye members. You can access them via a "visitor" function. But you still have to decide what to do when the visitor is not applied to the right type. I think you are not using Boost.Variant in the way that is intended to be used. (For example the conditionals don't smell well).
http://www.boost.org/doc/libs/1_61_0/doc/html/variant/reference.html#variant.concepts.static-visitor
struct hello_visitor : boost::static_visitor<>{
string const& msg;
hello_visitor(string const& msg) : msg(msg){}
void operator()(A::greeting& t) const{
t.hello = msg;
}
void operator()(B::greeting& t) const{
// throw? ignore? other?
}
};
struct bye_visitor : boost::static_visitor<>{
string const& msg;
bye_visitor(string const& msg) : msg(msg){}
void operator()(A::greeting& t) const{
// throw? ignore? other?
}
void operator()(B::greeting& t) const{
t.bye = msg;
}
};
greet getG(string key) {
greet g;
if (key == "A") { // is "key" handling the type, if so you can delegate this to the library instead of doing this.
boost::apply_visitor(hello_visitor("MY ENEMY"), g);
}
else {
boost::apply_visitor(bye_visitor("MY FRIEND"), g);
}
return g;
};
Hi i am trying to create a simple ORM in c++ for a project. For this example assuming a simple class as
class userProfile: public BaseOrm
{
public:
string username;
string email;
};
Now base orm has a method save() and migrate(). What i want is when a person calls migrate() all the schema , in this case username and email are populated as db tables and on save they persist on database.
What i am having problem with is how do i get what all fields are defined in the class, like in this example username and email and also there types, string in this case. Any help would be appreciated.
I know there is no reflection in c++, so i don't actually care about the variable name but more on the number of variables and there types to map them with DB.
adding reflection to c++ is not insanely difficult but it does require a reasonably good knowledge of template type deduction and some careful planning.
In this working example I have made a start for you. This framework supports writing the members out to a "statement" class (modelling a database prepared statement).
Similar techniques can be used to build out the SQL generation for CRUD.
No doubt there are already libraries that do this for you...
#include <iostream>
#include <iomanip>
#include <string>
#include <tuple>
#include <utility>
using namespace std;
struct statement
{
void setString(int index, const std::string& value)
{
std::cout << "setting index " << index << " to value " << std::quoted(value) << std::endl;
}
};
struct BaseOrm
{
virtual void serialise(statement& stmt) const = 0;
};
template<class Class>
struct class_tag {
using type = Class;
};
template<const char* Name>
struct name_tag {
static constexpr const char* name() { return Name; }
};
namespace detail {
struct reflection_item_concept
{
virtual const std::string& name() const = 0;
virtual std::string to_archive_string(const void* object) const = 0;
virtual void from_archive_string(void* object, const std::string& as) const = 0;
};
template<class T>
std::string to_archive_string_impl(const T& val) {
return std::to_string(val);
}
const std::string& to_archive_string_impl(const std::string& s) {
return s;
}
template<class NameTag, class Class, class Type>
struct reflection_item : reflection_item_concept
{
reflection_item(Type Class::* mfp) : mfp(mfp) {}
static const class_tag<Class> class_info() { return {}; };
static const char* raw_name() { return NameTag::name(); };
// concept implementation
const std::string& name() const override {
static const std::string s = raw_name();
return s;
}
std::string to_archive_string(const void* object) const override
{
auto& val = (*reinterpret_cast<const Class*>(object)).*mfp;
return to_archive_string_impl(val);
}
void from_archive_string(void* item, const std::string& as) const override
{
// similar mechanism here
}
Type Class::* mfp;
};
}
template<class NameTag, class Class, class Type>
constexpr auto reflection_item(NameTag, Type Class::* mp)
{
return detail::reflection_item<NameTag, Class, Type> { mp };
}
struct class_reflection_concept
{
virtual void serialise(const void* object, statement& stmt) const = 0;
};
namespace detail {
template<class ClassTag, class...ReflectionItems>
struct reflection_impl : class_reflection_concept
{
reflection_impl(ReflectionItems...refs)
: _reflectors(std::make_tuple(refs...))
{}
template<std::size_t...Is>
void serialise_impl(std::index_sequence<Is...>, const void* object,
statement& stmt) const
{
using expand = int[];
void(expand{
0,
(stmt.setString(Is + 1, std::get<Is>(_reflectors).to_archive_string(object)),0)...
});
}
void serialise(const void* object, statement& stmt) const override
{
serialise_impl(std::make_index_sequence<sizeof...(ReflectionItems)>(),
object, stmt);
}
std::tuple<ReflectionItems...> _reflectors;
};
}
template<class ClassTag, class...ReflectionItems>
auto& make_reflection(ClassTag tag, ReflectionItems...items)
{
static const detail::reflection_impl<ClassTag, ReflectionItems...> _ { items... };
return _;
}
const char txt_username[] = "username";
const char txt_email[] = "email";
const char txt_x[] = "x";
class userProfile: public BaseOrm
{
public:
string username = "test username";
string email = "noone#nowhere.com";
int x = 10;
// implement serialisation
void serialise(statement& stmt) const override
{
reflection.serialise(this, stmt);
}
static const class_reflection_concept& reflection;
};
const class_reflection_concept& userProfile::reflection =
make_reflection(class_tag<userProfile>(),
reflection_item(name_tag<txt_username>(), &userProfile::username),
reflection_item(name_tag<txt_email>(), &userProfile::email),
reflection_item(name_tag<txt_x>(), &userProfile::x));
int main()
{
userProfile x;
statement stmt;
x.serialise(stmt);
}
expected results:
setting index 1 to value "test username"
setting index 2 to value "noone#nowhere.com"
setting index 3 to value "10"
What I understand is that you want a generic behaviour for classes which have a variable set of fields.
I suggest you to create a "field" interface which will be stored in your base class with a container (for example a map of [fieldName, fieldInterface]). You still have to implement a behaviour for each field's type, but then you can create any class derived from the base class which have a dynamic set of field.
Here is an example :
#include <iostream>
#include <map>
using namespace std;
//the "Field" interface
class IFieldOrm
{
public:
virtual ~IFieldOrm() {}
virtual void save() = 0;
virtual void migrate() = 0;
};
//your base class
class BaseOrm
{
public:
virtual ~BaseOrm();
virtual void save();
virtual void migrate();
protected:
map<string, IFieldOrm*> m_fields; //prefer a smart pointer if you don't want to mess with raw pointer
};
//base class implementation
void BaseOrm::save()
{
for(auto& f : m_fields)
f.second->save();
}
void BaseOrm::migrate()
{
for(auto& f : m_fields)
f.second->migrate();
}
//don't forget to free your "fields" pointers if you have raw pointers
BaseOrm::~BaseOrm()
{
for(auto& f : m_fields)
delete f.second;
}
//then implement your basic types
//(like string, int, ..., whatever type you want to store in your database)
class StringFieldOrm : public IFieldOrm
{
public:
StringFieldOrm(const string& value) : m_value(value) {}
virtual void save();
virtual void migrate();
private:
string m_value;
};
void StringFieldOrm::save()
{
cout << "Save value " << m_value << endl;
//save stuff...
}
void StringFieldOrm::migrate()
{
cout << "Migrate value " << m_value << endl;
//migrate stuff...
}
class IntFieldOrm : public IFieldOrm
{
public:
IntFieldOrm(int& value) : m_value(value) {}
virtual void save();
virtual void migrate();
private:
int m_value;
};
void IntFieldOrm::save()
{
cout << "Save value " << m_value << endl;
//save stuff...
}
void IntFieldOrm::migrate()
{
cout << "Migrate value " << m_value << endl;
//migrate stuff
}
//and finally implement your final class
//note that this object can be "dynamically extended" by inserting new fields,
//you may want to prevent that and I can think of a solution if you want to
class UserProfile: public BaseOrm
{
public:
UserProfile(const string& username, const string& email, int age);
};
UserProfile::UserProfile(const string& username, const string& email, int age)
{
m_fields["username"] = new StringFieldOrm(username);
m_fields["email"] = new StringFieldOrm(email);
m_fields["age"] = new IntFieldOrm(age);
}
int main(int argc, char* argv[])
{
UserProfile user = UserProfile("Batman", "bw#batmail.com", 30);
user.save();
return 0;
}
create a userProfile variable and access them:
userProfile user;
int main(){
std::cout << user.username;
std::cout << user.email ;
}
this is how you would access them, except for different reasons, not printing them to the screen.
I'm developing a library that parses a certain XML file (using RapidXML) and returns an object of mine, containing that file data. That XML file is created by someone else's application. I needed to use the observer pattern because speed is extremely crucial, for example:
Suppose a file has 10.000 tag and its child nodes. In a simple parser, they would be added to a std::vector in the order they were found. Then, after the file was parsed, we would need to iterate over the 10.000 values AGAIN and do whatever we want with them.
By using the observer pattern, I allow external observers (whichever class that wants to observe and be notified about each fetched node has to inherit from AbstractObserver that comes with my library, and implement his functions) to be a part of the parsing process without the need to iterate X times again over the parsed nodes. HOWEVER... There are multiple kinds of nodes, for example: tileset, layer, imagelayer and so on (being necessary multiple onObserved and notify functions for its corresponding node, according to the Observer/Subject pattern, probably having a lot of 'duplicated' code - NOTE: inheritance is not used. See bellow a 'bad' example). I could simply make the nodes inherit from some sort of BaseNode class, but I dont want to use inheritance here since I dont want to deal with pointers. Instead, I'm using enums to type the nodes and thats where my problem lies.
/* ################## ABSTRACT OBSERVER #################### */
// Implements the observer pattern, using the CRTP pattern
template<class ConcreteObserver>
class AbstractObserver
{
public:
virtual ~AbstractObserver() { }
template<class Attribute>
inline void onObserved(Attribute attribute) {
// This requires ConcreteObserver to have a method onObservedImpl<Attribute>
static_cast<const ConcreteObserver*>(this)->onObservedImpl(attribute);
}
};
/* ################## ABSTRACT SUBJECT #################### */
class AbstractSubject
{
public:
virtual ~AbstractSubject() { }
// ???????
inline void attach(AbstractObserver<??????>* observer) {
m_observers.push_back(observer);
}
// ???????
inline void detatch(AbstractObserver<??????>* observer) {
auto& it = std::find(m_observers.begin(), m_observers.end(), observer);
// Remove the observer from the list, if it was observing
if (it != m_observers.end())
m_observers.erase(it);
}
protected:
template<typename Attribute>
void notify(Attribute& attribute) {
for (auto* observer : m_observers)
observer->onObserved(attribute)
}
private:
// ???????
std::vector<AbstractObserver<??????>*> m_observers;
};
/* ################## CONCRETE OBSERVER #################### */
class SomeConcreteObserver : public AbstractObserver<SomeConcreteObserver>
{
public:
// The CRTP 'virtual' function implementation
template<class Attribute>
void onObservedImpl(Attribute attribute)
{
// Filter the attribute and use it accordingly
switch (attribute.type)
{
// ....
}
}
};
/* ################## CONCRETE SUBJECT #################### */
class Parser : public AbstractSubject
{
public:
void parse(/* params */)
{
Foo f;
notify<Foo>(f);
// Later on....
Bar b;
notify<Bar>(b);
}
};
As we can see, I'm using the CRTP as well, since I need 'templated virtual functions', which is impossible to achieve otherwise. Since the AbstractObserver needs a type (because of the CRTP), I can't properly use them in the AbstractSubject class (see above). Is it even possible to use annonymous templates just like Java, or something like that? I believe this WOULD do the job.
Here is the implementation of a 'bad' example I thought of, but this is the best I could come up with for this situation:
// Remove the CRTP
class AbstractObserver
{
public:
virtual ~AbstractObserver() { }
virtual void onNodeA(NodeA n) = 0;
virtual void onNodeB(NodeB n) = 0;
virtual void onNodeC(NodeC n) = 0;
virtual void onNodeD(NodeD n) = 0;
virtual void onNodeE(NodeE n) = 0;
// .....
};
class AbstractSubject
{
public:
// ....
protected:
void notifyNodeA(NodeA n) {
for (auto* observer : m_observers)
observer->onNodeA(n);
}
void notifyNodeB(NodeB n) {
for (auto* observer : m_observers)
observer->NodeB(n);
}
void notifyNodeC(NodeC n) { }
void notifyNodeD(NodeD n) { }
void notifyNodeE(NodeE n) { }
// ....
private:
std::vector<Observer*> m_observers;
};
The solution has to use C++11 or bellow and no boost.
Solution #1: Quite wet but simple
#include <vector>
#include <algorithm>
#include <iostream>
template<typename TAttribute>
class Observer
{
public:
virtual void Observe(TAttribute& attribute) = 0;
virtual ~Observer() = default;
};
template<typename TAttribute>
class OutputtingObserver : public Observer<TAttribute>
{
public:
void Observe(TAttribute& attribute)
{
std::cout << attribute << std::endl;
}
~OutputtingObserver() = default;
};
template<typename TAttribute>
class Subject
{
private:
std::vector<Observer<TAttribute>*> mutable m_observers;
public:
void Attach(Observer<TAttribute>& observer) const
{
m_observers.push_back(&observer);
}
void Detach(Observer<TAttribute>& observer) const
{
m_observers.erase(std::remove(m_observers.begin(), m_observers.end(), &observer), m_observers.end());
}
void Notify(TAttribute& attribute)
{
for (auto observer : m_observers)
observer->Observe(attribute);
}
};
class NodeA
{
public:
friend std::ostream& operator<<(std::ostream& o, const NodeA& node)
{
return o << "a";
}
};
class NodeB
{
public:
friend std::ostream& operator<<(std::ostream& o, const NodeB& node)
{
return o << "b";
}
};
class Parser
{
private:
Subject<NodeA> m_subjectA;
Subject<NodeB> m_subjectB;
public:
void Parse()
{
auto a = NodeA();
auto b = NodeB();
m_subjectA.Notify(a);
m_subjectB.Notify(b);
}
void Attach(Observer<NodeA>& observer)
{
m_subjectA.Attach(observer);
}
void Attach(Observer<NodeB>& observer)
{
m_subjectB.Attach(observer);
}
};
int main()
{
auto observerA = OutputtingObserver<NodeA>();
auto observerB = OutputtingObserver<NodeB>();
auto parser = Parser();
parser.Attach(observerA);
parser.Attach(observerB);
parser.Attach(observerA);
parser.Parse();
return 1;
}
You would need to use composition here and have a subject for each type of node. However, this is compile-time validated so I'd prefer this to the second version.
Solution #2: Dynamic and closer to what you want
#include <unordered_map>
#include <vector>
#include <algorithm>
#include <iostream>
class ObserverBase
{
public:
virtual ~ObserverBase() = default;
};
template<typename TAttribute>
class Observer : public ObserverBase
{
public:
virtual void Observe(TAttribute& attribute) = 0;
};
template<typename TAttribute>
class OutputtingObserver : public Observer<TAttribute>
{
public:
void Observe(TAttribute& attribute)
{
std::cout << attribute << std::endl;
}
~OutputtingObserver() = default;
};
template<typename TKey>
class Subject
{
private:
using ObserverList = std::vector<ObserverBase*>;
using ObserverMap = std::unordered_map<TKey, ObserverList>;
ObserverMap mutable m_observers;
public:
void Attach(TKey key, ObserverBase& observer) const
{
auto itr = m_observers.find(key);
if (itr == m_observers.end())
{
m_observers.emplace(std::make_pair(key, ObserverList { &observer }));
return;
}
itr->second.push_back(&observer);
}
void Detach(ObserverBase& observer) const
{
m_observers.erase(std::remove(m_observers.begin(), m_observers.end(), &observer), m_observers.end());
}
template<TKey key, typename TAttribute>
void Notify(TAttribute& attribute)
{
auto itr = m_observers.find(key);
if (itr == m_observers.end())
return;
for (auto observer : itr->second)
dynamic_cast<Observer<TAttribute>*>(observer)->Observe(attribute);
}
};
enum class NodeType
{
TypeA,
TypeB
};
class NodeA
{
public:
friend std::ostream& operator<<(std::ostream& o, const NodeA& node)
{
return o << "a";
}
};
class NodeB
{
public:
friend std::ostream& operator<<(std::ostream& o, const NodeB& node)
{
return o << "b";
}
};
class Parser
{
private:
Subject<NodeType> m_subject;
public:
void Parse()
{
auto a = NodeA();
auto b = NodeB();
m_subject.Notify<NodeType::TypeA, NodeA>(a);
m_subject.Notify<NodeType::TypeB, NodeB>(b);
}
void Attach(Observer<NodeA>& observer)
{
m_subject.Attach(NodeType::TypeA, observer);
}
void Attach(Observer<NodeB>& observer)
{
m_subject.Attach(NodeType::TypeB, observer);
}
};
int main()
{
auto observerA = OutputtingObserver<NodeA>();
auto observerB = OutputtingObserver<NodeB>();
auto parser = Parser();
parser.Attach(observerA);
parser.Attach(observerB);
parser.Attach(observerA);
parser.Parse();
return 1;
}
This is closer to your version. Quite unsafe and slower but slightly less typing.
Summary
Both output a\na\nb and both are something sewn together just as a minimal proof of concept, not something you should follow (especially the working with unordered_map feels quite nasty).
It's not directly what you want but I guess that you can take it from there...
I have strong feeling that there are better solutions to this so feel free to experiment.
EDIT:
Solution #3: Completely dynamic
#include <unordered_map>
#include <vector>
#include <algorithm>
#include <iostream>
#include <typeinfo>
#include <typeindex>
template<typename TAttribute>
class Observer
{
public:
virtual void Observe(TAttribute& attribute) = 0;
virtual ~Observer() = default;
};
class Subject
{
private:
using ObserverList = std::vector<void*>;
using ObserverMap = std::unordered_map<std::type_index, ObserverList>;
ObserverMap mutable m_observers;
public:
template<typename TAttribute>
void Attach(Observer<TAttribute>& observer) const
{
auto index = std::type_index(typeid(Observer<TAttribute>));
auto itr = m_observers.find(index);
if (itr == m_observers.end())
{
m_observers.emplace(std::make_pair(index, ObserverList { &observer }));
return;
}
itr->second.push_back(&observer);
}
template<typename TAttribute>
void Detach(Observer<TAttribute>& observer) const
{
m_observers.erase(std::remove(m_observers.begin(), m_observers.end(), &observer), m_observers.end());
}
template<typename TAttribute>
void Notify(TAttribute& attribute)
{
auto itr = m_observers.find(std::type_index(typeid(Observer<TAttribute>)));
if (itr == m_observers.end())
return;
for (auto observer : itr->second)
static_cast<Observer<TAttribute>*>(observer)->Observe(attribute);
}
};
This is basically a ported C#'s version of Dictionary<Type, Object>, it uses rtti so you might get spat on by C++ hardliners...
I have 2 simple C++ headers implemented as in the following:
Attribute.h
#include <string>
using namespace std;
class IAttribute
{
virtual string getName(){};
};
class StringAttribute : public IAttribute
{
private:
string name = "";
string value = "";
public:
StringAttribute(string name, string value)
{
this->name = name;
this->value = value;
}
string getName()
{
return this->name;
}
string getStrValue()
{
return value;
}
void setValue(string value)
{
this->value = value;
}
};
tableRow.h
#include "attribute.h"
#include <vector>
using namespace std;
class TableRow
{
private:
vector<IAttribute *> attributeList;
int rowId;
public:
TableRow(int rowId)
{
this->rowId = rowId;
}
void addStrAttribute(string name, string value)
{
attributeList.push_back(new StringAttribute(name, value));
}
StringAttribute getStrAtt(string name)
{
for (int i = 0; i < (int)attributeList.size(); i++)
{
if (attributeList[i]->)//couldn't access the methods of StringAttributeImp
{
}
}
}
};
As in the comment of tableRow header above, I couldn't access the methods and properties of the Implementation class. What is wrong?
The getName function is private in the IAttribute class. So of course you're not able to access it.
You should change the getName function to public; or use friend class.