C++ Signal and Slot not working: slot not responding to event - c++

I am creating a Signal and Slot system with a design like this:
There is the signal and slot classes
struct timeDoubleEvent
{
public:
timeDoubleEvent(const std::string& dataName)
:
dataName(dataName)
{}
const std::string& getDataName() const { return dataName; }
Event<hydraPtr<DataHandler::timeDouble>> update;
void fire(const hydraPtr<DataHandler::timeDouble>& timeDouble) const { update(timeDouble); }
private:
const std::string dataName;
};
class timeDoubleSlot
{
public:
timeDoubleSlot(const std::string& dataName)
:
dataName(dataName)
{}
const std::string& getDataName() const { return dataName; }
virtual void onEvent(const hydraPtr<DataHandler::timeDouble>& timeDouble) = 0;
private:
const std::string dataName;
};
The slot would eventually differ for various cases, so I am creating derived class of it nested inside something:
class BaseClass
{
// forward declaration
class timePriceSlot;
public:
BaseClass(const std::string& name,
const std::vector<hydraPtr<EventHandler::timeDoubleEvent>>& dataEventVector,
const size_t& warmUpLength)
:
name(name),
dataSlotVector(initializeDataSlotVector(dataEventVector)),
warmUpLength(warmUpLength),
dataStorage(initializeDataStorage(dataEventVector)),
timeStorage(initializeTimeStorage(dataEventVector))
{}
private:
const std::vector<hydraPtr<timePriceSlot>> dataSlotVector;
const std::vector<hydraPtr<timePriceSlot>> initializeDataSlotVector(const std::vector<hydraPtr<EventHandler::timeDoubleEvent>>&);
const bool& checkAllDataReceived(const std::string& dataName);
class timePriceSlot : public EventHandler::timeDoubleSlot
{
public:
timePriceSlot(const std::string& dataName,
BaseClass& parent)
:
timeDoubleSlot(dataName),
parent(parent)
{}
void onEvent(const hydraPtr<DataHandler::timeDouble>& timeDouble);
BaseClass& getParent() const { return parent; }
private:
BaseClass& parent;
};
};
(only showing the relevant bits) In particular, the signal-slot connection is done like this:
const std::vector<hydraPtr<BaseClass::timePriceSlot>> BaseClass::initializeDataSlotVector(
const std::vector<hydraPtr<EventHandler::timeDoubleEvent>>& dataEventVector)
{
std::vector<hydraPtr<BaseClass::timePriceSlot>> output(dataEventVector.size());
for (size_t i = 0; i < dataEventVector.size(); ++i)
{
EventHandler::timeDoubleEvent thisTimeDoubleEvent = (*dataEventVector[i]);
std::shared_ptr<BaseClass::timePriceSlot> thisTimePriceSlot = std::make_shared<BaseClass::timePriceSlot>(dataEventVector[i]->getDataName(), *this);
output[i] = thisTimePriceSlot;
thisTimeDoubleEvent.update.connect([&](hydraPtr<DataHandler::timeDouble>& timeDouble) { (*thisTimePriceSlot).onEvent(timeDouble); });
}
return output;
}
I am calling the function with a client program like this:
const std::string stockName = "BBH";
EventHandler::timeDoubleEvent event1(stockName);
std::vector<hydraPtr<EventHandler::timeDoubleEvent>> eventVector(1);
eventVector[0] = std::make_shared<EventHandler::timeDoubleEvent>(stockName);
const hydraPtr<Signal::DerivedClass> myMA = std::make_shared<Signal::DerivedClass>(stockName + "_MA", eventVector, 10);
const std::vector<hydraPtr<DataHandler::PriceTimeSeriesDataStruct>> myData = getAggregatedData();
const std::vector<double> priceVectorCopy = myData[0]->getPriceVector();
std::vector<double>::const_iterator it_d;
const std::vector<std::string> timeVectorCopy = myData[0]->getDateTimeVector();
std::vector<std::string>::const_iterator it_s;
for (it_d = priceVectorCopy.begin(), it_s = timeVectorCopy.begin();
it_d != priceVectorCopy.end(); it_d++, it_s++)
{
const hydraPtr<DataHandler::timeDouble> timeDoubleTemp = std::make_shared<DataHandler::timeDouble>(stockName, (*it_s), (*it_d));
event1.fire(timeDoubleTemp);
}
(DerivedClass is derived from BaseClass, with a different implementation of one function not relevant here) However, I found that even though there is no build or run time error, nothing happens upon the event fire. In fact, the onEvent function is never visited. Have I done something wrong? Thanks in advance.

The problem was in this line
thisTimeDoubleEvent.update.connect([&](hydraPtr<DataHandler::timeDouble>& timeDouble) { (*thisTimePriceSlot).onEvent(timeDouble); });
Both the event and the slot should be pointers, not dereferenced values.

Related

Namespace Implementation

I am trying to implement the functionality of namespaces. The main class Project contains a vector std::vector std::shared_ptr<Class>classes_{}; Each class, respectively, contains similar vectors with Variable and Function. Also, the Class class can have a base class - Class* parent_. The task is such, for example, when adding a new variable (in Class std::vector std::shared_ptr<Variable> vars_{};) or renaming an existing one, it was checked (taking into account visibility) that a variable with such a name does not exist in this class and all his ancestors. The names of the created functions and classes were also checked, etc.
Below is my implementation that I don't like.
Variable::parent_ can be both a class and a function. It is logical to assume that Class, if it does not have a parent class, parent_ was not nullptr, but Project*. In principle, this can be solved by having all classes store Nameable* parent_ rather than a concrete class. But then every time you access parent_ you would have to downcast the pointer.
Traversing all Nameable objects creates a set of temporary vectors (in Nameable::nameables() and in Nameable::get_nameables()).
Please advise how to solve these problems. Or perhaps where you can peep a more beautiful implementation
#include "string"
#include "string_view"
#include "vector"
#include <iostream>
#include <memory>
class Nameable
{
std::string name_{};
//VISIBILITY visibility_{ VISIBILITY::PUBLIC };
protected:
virtual Nameable* parent() const = 0;
virtual std::vector<std::shared_ptr<Nameable>> nameables() const = 0;
void get_nameables(std::vector<std::shared_ptr<Nameable>>& n)
{
std::vector<std::shared_ptr<Nameable>> names = nameables();
if (parent())
parent()->get_nameables(names);
n.insert(n.end(), names.begin(), names.end());
}
public:
Nameable(std::string_view name) : name_(name)
{
//if (!check_name(name)) throw InvalidNameException(name);
}
virtual ~Nameable() {};
std::shared_ptr<Nameable> check_name(std::string_view name) const
{
return std::shared_ptr<Nameable>();
}
const std::string& get_name() const& { return name_; }
void set_name(std::string_view name) { name_ = name; }
};
class Variable;
class Function;
class Class final : public Nameable
{
std::vector<std::shared_ptr<Variable>> vars_{};
std::vector<std::shared_ptr<Function>> funs_{};
Class* parent_{};
Nameable* parent() const override
{
return parent_;
}
std::vector<std::shared_ptr<Nameable>> nameables() const override
{
std::vector<std::shared_ptr<Nameable>> n{};
n.insert(n.end(), vars_.begin(), vars_.end());
n.insert(n.end(), funs_.begin(), funs_.end());
return n;
}
public:
Class(std::string_view name, Class* parent = nullptr)
: Nameable(name), parent_(parent)
{}
std::shared_ptr<Variable> create_var(std::string_view name)
{
vars_.push_back(std::make_shared<Variable>(name, this));
return vars_.back();
}
std::shared_ptr<Function> create_fun(std::string_view name)
{
funs_.push_back(std::make_shared<Function>(name, this));
return funs_.back();
}
};
class Variable final : public Nameable
{
Class* parent_{};
Nameable* parent() const override
{
return parent_;
}
std::vector<std::shared_ptr<Nameable>> nameables() const override
{
std::vector<std::shared_ptr<Nameable>> n{};
return n; // return empty vector
}
public:
Variable(std::string_view name, Class* parent)
: Nameable(name), parent_(parent) {}
};
class Function final : public Nameable
{
Class* parent_{};
std::vector<std::shared_ptr<Variable>> local_vars_{};
Nameable* parent() const override
{
return parent_;
}
std::vector<std::shared_ptr<Nameable>> nameables() const override
{
std::vector<std::shared_ptr<Nameable>> n{};
n.insert(n.end(), local_vars_.begin(), local_vars_.end());
return n;
}
public:
Function(std::string_view name, Class* parent)
: Nameable(name), parent_(parent) {}
};
class Project final : public Nameable
{
std::vector<std::shared_ptr<Class>> classes_{};
Nameable* parent() const override { return nullptr; }
std::vector<std::shared_ptr<Nameable>> nameables() const override
{
std::vector<std::shared_ptr<Nameable>> n{};
n.insert(n.end(), classes_.begin(), classes_.end());
return n;
}
public:
Project(std::string_view name) : Nameable(name){}
};
I'm not sure if I understand your intent clearly, yet maybe use composition instead? It's just easier to maintain. It'd be easier for me if you have provided any use case, but nonetheless I have something like below for you.
// You may want use it in a bitfield mask manner.
enum class NameType : int8_t {
Function = 1,
Variable = 2,
Object = 4,
None = 8
};
// Just simple storage, defaulted if constructed with a default constructor.
struct Nameable {
// union := variable | static_function
using Parent = std::variant<std::optional<std::any>, std::function<std::any(std::any)>>;
explicit Nameable(std::string_view sv, NameType t, const Parent& p = std::nullopt): name(sv), type(t), parent(p)
{
}
std::string name{};
NameType type = NameType::None;
Parent parent = std::nullopt;
};
// Flat aggregator of names (no hierarchy mapping), one-for-all (e.g. per class, per namespace).
struct Collector {
using Nameables = std::vector<std::optional<Nameable>>;
explicit Collector(std::string_view sv, NameType t, const std::optional<std::any>& p = std::nullopt)
{
attach(sv, t, p);
}
void attach(std::string_view sv, NameType t, const std::optional<std::any>& p = std::nullopt)
{
auto n = Nameable(sv, t, p);
names.emplace_back(std::move(n));
}
// combine collectors, such that (f+g)(n) := f(n) + g(n), e.g. for namespace, module, translation unit.
[[maybe_unused]] void attach(const Collector& c)
{
for (const auto& name: c.names) {
attach(name->name, name->type, name->parent);
}
}
bool isUniqueName(std::string_view key) const
{
return std::ranges::all_of(names, [key](const auto& name) {
if (name.has_value() && name.value().name == key) return false;
return true;
});
}
bool isUniqueObjectName(std::string_view key) const
{
return std::ranges::all_of(names, [key](const auto& name) {
if (name.has_value() && name.value().type == NameType::Object && name.value().name == key) return false;
return true;
});
}
std::size_t index(std::string_view key) const
{
for (std::size_t i = 0; i != names.size(); ++i) {
const auto& name = names[i];
if (name.has_value() && name.value().name == key) return i;
}
return std::string::npos;
}
void rename(std::string_view from, std::string_view to)
{
names.at(index(from)).value().name = std::string(to);
}
const Nameable& get(std::string_view key) const
{
if (!names.at(index(key)).has_value()) throw std::bad_optional_access();
return names.at(index(key)).value();
}
std::any variable(std::string_view name) const
{
const auto& nameable = get(name);
if (const auto& var = nameable.parent; std::holds_alternative<std::optional<std::any>>(var)) {
if (const auto& opt = std::get<0>(var); opt.has_value()) return opt.value();
throw std::bad_optional_access();
}
throw std::bad_variant_access();
}
Nameables names{};
};
The idea is to collect names hierarchically but through "formation". Alternatively, just use trees, or dictionaries (as it has been already stated).
namespace outer {
Collector cOuter;
constexpr int GLOBAL = 1;
namespace inner {
Collector cInner;
void f() {}
namespace internal {
Collector cInternal;
Data d{};
}
}
}
I'm not certain if you're really interested in storing objects, though.
With std::any it may require some gymnastic, but you can handle it.
I would suggest std::optional, but this need trivially copyable structure, so be careful with adding new fields. Collecting member functions require some additional std::function signature. If you need more information, e.g. about types, then store them as type traits, or concepts, or anyhow. Eventually, introduce std::variant<Variable, Function, Class/Object>. Let give them do their job (Variable/+types, Function/+params, Class/+hierarchy) and compose them at the end.
struct SomeClass {
static auto Something(int y = 3) noexcept
{
return 1 + y;
}
int var1 = 0;
float var2 = 5.5;
};
SomeClass s{};
auto c = Collector("SomeClass", NameType::Object, s);
c.attach("var1", NameType::Variable, s.var1);
c.attach("var2", NameType::Variable, s.var2);
c.attach("Something", NameType::Function, SomeClass::Something);
std::cout << c.names[0].value().name << '\n'; // "SomeClass", etc.
std::cout << std::boolalpha << c.isUniqueName("var1") << '\n'; // false
c.rename("var1", "var_1");
std::cout << std::boolalpha << c.isUniqueName("var1") << '\n'; // true
std::cout << std::boolalpha << c.isUniqueObjectName("SomeClass") << '\n'; // false
auto var2 = c.variable("var2");
auto vf = std::any_cast<float>(var2);
std::cout << std::to_string(vf) << '\n'; // 5.500000

Ideas on getting rid of boiler plate code

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)
};

Observer const-correctness

I am trying to implement observer pattern into my project.
Imagine simple a class method
const Buffer * data() const
{
if (m_data)
return m_data;
// read some data from input
m_data = fstream.read(1000);
// subscribe to our buffer
m_data->Subscribe(this);
return m_data;
}
This method is used to read input data, but the operation could be time consuming, it is therefore delayed.
Class Buffer is simple wrapper above std::vector, which notifies observers, when it's data being altered.
The containing class needs to be notified, when Buffer data changes.
However, since this method is marked as const, I am unable to subscribe to the Buffer.
I was able to figure out 3 solutions:
1. Cast away const-ness
// subscribe to our buffer
m_data->Subscribe(const_cast<Object*>(this));
I am not sure, whether this is correct, but it works.
2. Change const-ness of notification method and observers
vector<const IModifyObserver*> m_observers;
void Subscribe(const IModifyObserver* observer);
void Unsubscribe(const IModifyObserver* observer)
virtual void ObserveeChanged(IModifyObservable*) const override
{
m_dirty = true;
}
This one has a downfall, if I need to change properties they all have to be mutable and all functions I call must be const, which also does not make any sense.
3. Remove const from everywhere
Buffer * data();
bool Equals(Object& other);
Buffer* m_data;
This would most probably mean, that I would have to remove const from whole solution, since I can't event call Equals for two different const objects.
How to properly solve this problem?
Full Code:
#include <vector>
using namespace std;
class IModifyObservable;
// class for receiving changed notifications
class IModifyObserver
{
public:
virtual void ObserveeChanged(IModifyObservable* observee) = 0;
virtual ~IModifyObserver() = 0;
};
// class for producing changed notifications
class IModifyObservable
{
public:
// Add new subscriber to notify
void Subscribe(IModifyObserver* observer)
{
m_observers.push_back(observer);
}
// Remove existing subscriber
void Unsubscribe(IModifyObserver* observer)
{
for (auto it = m_observers.begin(); it != m_observers.end(); ++it) {
if (observer == *it) {
m_observers.erase(it);
break;
}
}
}
// Notify all subscribers
virtual void OnChanged()
{
auto size = m_observers.size();
for (decltype(size) i = 0; i < size; ++i) {
m_observers[i]->ObserveeChanged(this);
}
}
virtual ~IModifyObservable() = 0;
private:
vector<IModifyObserver*> m_observers;
};
IModifyObserver::~IModifyObserver() {}
IModifyObservable::~IModifyObservable() {}
// Example class implementing IModifyObservable
class Buffer : public IModifyObservable
{
private:
vector<char> m_data;
};
// Example class implementing IModifyObserver
class Object : public IModifyObserver
{
public:
// Both share implementation
//Buffer * data();
const Buffer * data() const
{
// Just read some data
//m_data = fstream.read(1000);
// Subscribe to our buffer
m_data->Subscribe(this);
return m_data;
}
virtual void ObserveeChanged(IModifyObservable*) override
{
m_dirty = true;
}
// This is just for example, why do I need const data method
bool Equals(const Object& other) const { return data() == other.data();
}
private:
mutable Buffer* m_data = new Buffer();
bool m_dirty;
};
int main()
{
Object obj1;
Object obj2;
auto data1 = obj1.data();
auto data2 = obj2.data();
bool equals = (obj1.Equals(obj2));
}
What gets in the way here is you deferred reading. Without this optimisation the right way would be to separate constant and non-constant methods:
const Buffer * data() const
{
return m_data;
}
void InitializeData()
{
// Just read some data
m_data = fstream.read(1000);
// Subscribe to our buffer
m_data->Subscribe(this);
}
Then optimize it the way you want:
const Buffer * data() const
{
if(m_data == nullptr)
const_cast<Object*>(this)->InitializeData();
return m_data;
}
And you don't need m_data to mutable anymore.
BTW. To make this deferred initialization work you should initialize m_data member with nullptr. Otherwise this object will be created while constructing and your if(m_data) will be always true.
UPD
So here is another solution to your problem
class Object : public IModifyObserver
{
public:
Object()
: m_data(nullptr)
, m_dataInitialized(false)
// ...
{
m_data = new Buffer(); // << Create buffer here
m_data->Subscribe(this); // << And subscribe right away
}
const Buffer * data() const
{
if(!m_dataInitialized) // << Initialize if needed
{
// Set data here
m_data->setData(fstream.read(1000)); // << Probably you want to suppress notifications here
m_dataInitialized = true;
}
return m_data;
}
// ...
private:
mutable Buffer* m_data;
mutable bool m_dataInitialized; // << Added another flag to see if data was initialized
// ...
};
I took the liberty of refactoring your code, I couldn't see where the initial call to data() would happen in your example, but I imagine it is called in a 2-phase way (construct -> then call method). Sticking with the simple rule..
#include <algorithm>
#include <memory>
#include <vector>
using namespace std;
class IModifyObservable;
// class for receiving changed notifications
class IModifyObserver
{
public:
virtual void ObserveeChanged(IModifyObservable* observee) = 0;
virtual ~IModifyObserver() = default;
};
// class for producing changed notifications
class IModifyObservable
{
public:
// This method modifies state - so non-const
void Subscribe(IModifyObserver* observer)
{
observers_.push_back(observer);
}
// This method modifies state - so non-const
void Unsubscribe(IModifyObserver* observer)
{
observers_.erase(find(begin(observers_), end(observers_), observer));
}
// Again as the internal state of the observer is modified, this is non-const
virtual void OnChanged()
{
for (auto observer : observers_) {
observer->ObserveeChanged(this);
}
}
virtual ~IModifyObservable() = default;
private:
vector<IModifyObserver*> observers_;
};
// Example class implementing IModifyObservable
class Buffer : public IModifyObservable
{
vector<char> data_;
};
// Example class implementing IModifyObserver
class Object : public IModifyObserver
{
public:
// The first call to the non-cost version triggers the lazy load...
const Buffer* data()
{
if (!data_) {
data_ = make_unique<Buffer>();
// Now start the read operation
// :
// Subscribe, I imagine you only want to do this once?
data_->Subscribe(this);
}
return data_.get();
}
// Calls to const version returns what's there...
const Buffer* data() const
{
return data_.get();
}
// This has to be non-cost as the internal state is being modified
void ObserveeChanged(IModifyObservable*) override
{
dirty_ = true;
}
// Operator uses const versions, which will use const methods
friend
bool operator==(const Object& lhs, const Object& rhs) {
if (lhs.data() && rhs.data()) {
}
return false;
}
private:
unique_ptr<Buffer> data_;
bool dirty_ = false;
};
int main()
{
Object obj1;
Object obj2;
auto data1 = obj1.data();
auto data2 = obj2.data();
bool equals = obj1 == obj2;
}
There are no hacks, it should just work...
Avoid to register in the a getter, register in initialization:
class Object : public IModifyObserver
{
public:
Object() { m_data.Subscribe(this); }
const Buffer* data() const { return m_data; }
Buffer* data() { return m_data; }
void ObserveeChanged(IModifyObservable*) override { m_dirty = true; }
private:
Buffer m_data;
bool m_dirty = false;
};
With lazy initialization, it becomes:
class Object : public IModifyObserver
{
public:
Object() { m_data.Subscribe(this); }
Buffer& data()
{
if (!m_data.is_initialized()) { m_data.initialize(); }
return m_data;
}
const Buffer& data() const
{
if (!m_data.is_initialized()) { m_data.initialize(); }
return m_data;
}
void ObserveeChanged(IModifyObservable*) override { m_dirty = true; }
private:
mutable Buffer m_data;
bool m_dirty = false;
};
Demo

Modify const parameter reference

Ok so I have two classes that look like:
class Item
{
private:
HANDLE Parent;
public:
Item(const Item &I) = delete;
Item(Item &&I) = delete;
void SetParent(HANDLE Handle);
Item& operator = (const Item &I) = delete;
Item& operator = (Item &&I);
};
void Item::SetParent(HANDLE Handle)
{
this->Parent = Handle;
}
Item& Item::operator = (Item&& I) {/*Do Move Here*/}
class Box
{
private:
HANDLE Handle;
public:
void Add(const Item &I);
};
void Box::Add(const Item &I)
{
I.SetParent(this->Handle); //Error.. Item I is const.
}
I get the error that I is const and that makes sense but I need a way to SetParent of Item I without losing the ability to construct I in place as so:
Box B(Item());
instead of:
Item I;
Box B(I);
Any ideas how I can keep inline construction of I while being able to modify it by calling SetParent?
A solution is to declare the Parent member as mutable and to make the SetParent method constant. A sample code is following and available online
typedef int HANDLE;
class Item
{
private:
mutable HANDLE Parent;
public:
Item(const Item &I) = delete;
Item(Item &&I) = delete;
void SetParent(HANDLE Handle) const;
Item& operator = (const Item &I) = delete;
Item& operator = (Item &&I);
};
void Item::SetParent(HANDLE Handle) const
{
this->Parent = Handle;
}
class Box
{
private:
HANDLE Handle;
public:
void Add(const Item &I);
public:
Box(const Item &I) {
Add(I);
}
};
void Box::Add(const Item &I)
{
I.SetParent(this->Handle); //Error.. Item I is const.
}
int main(void) {
return 0;
}

C++ Nested forward declaration inheritence

My issue is :
I define class (generator) inside of which I define a forward nested structs (topics and it_set).
I make the declaration of this nested class inside the .cpp file.
After this I declare a second class (ImageGenerator) which is an inheritence of generator.
I get an issue when I try inside of the declaration file of ImageGenerator.
Is there anyway to make that possible ?
My codes are these :
<i>
//base.hpp
</i>
class generator{
protected:
struct topics;
struct it_set;
NodeHandle _nh;
cv::Ptr<topics> _topics;
cv::Ptr<it_set> _set;
cv::Mat _data;
public:
generator(ros::NodeHandle&,const std::string&,const std::string&,const std::string&);
virtual ~generator(void);
bool ok(void)const;
protected:
virtual void grab(void) = 0;
};
<i>
// base.cpp
</i>
static void cam_from_sub(const std::string& _subscriber,std::string& _cam){
std::stringstream str;
std::vector<std::string> words;
std::string tmp;
for(std::string::const_iterator it = _subscriber.begin();it != _subscriber.end();it++)
(*it != '/')?(str<<*it):(str<<std::endl);
while(!str.eof()){
str>>tmp;
words.push_back(tmp);
tmp.clear();
}
words.pop_back();
for(std::vector<std::string>::iterator it = words.begin(); it != words.end();it++){
_cam+=*it+std::string("/");
it->clear();
}
words.clear();
_cam+= std::string("camera_info");
}
struct generator::topics{
std::string _publisher;
std::string _subscriber;
std::string _camera_info;
topics(const std::string& _pub,const std::string& _sub,const std::string& _cam):_publisher(_pub),_subscriber(_sub),_camera_info(_cam){}
topics(const std::string &_pub, const std::string &_sub):_publisher(_pub),_subscriber(_sub){cam_from_sub(_subscriber,_camera_info);}
~topics(void){}
};
struct generator::it_set{
image_transport::ImageTransport _it;
image_transport::SubscriberFilter _is;
image_transport::Publisher _pb;
message_filters::Subscriber<sensor_msgs::CameraInfo> _cam_info;
it_set(NodeHandle& _nh,cv::Ptr<generator::topics>& _topics):_it(_nh),_is(_it,_topics->_subscriber,1),_cam_info(_nh,_topics->_camera_info,1){ this->_pb = this->_it.advertise(_topics->_publisher,1);}
};
generator::generator(NodeHandle & nh, const std::string & subscribe, const std::string & publish, const std::string & camera_info):_nh(nh),_topics(new topics(publish,subscribe,camera_info)),_set( new it_set(_nh,_topics)){}
generator::~generator(void){ _set.release(); _topics.release();}
bool generator::ok(void)const{ return this->_nh.ok();}
<i>
// image.hpp
</i>
class ImageGenerator : public generator{
private:
NodeHandle _nh;
static bool _sht;
bool _first_sht;
bool _is_sub;
public:
typedef void(*function_type)(const cv::Mat&,cv::Mat&);
private:
function_type _fun;
virtual void callback(const sensor_msgs::ImageConstPtr&);
virtual void grab(void);
public:
ImageGenerator(const NodeHandle&,const std::string&,const std::string&,const std::string&,function_type);
~ImageGenerator(void);
void operator>>(cv::Mat&);
void operator<<(const cv::Mat&);
};
<i>
// image.cpp
</i>
bool ImageGenerator::_sht = false;
void ImageGenerator::grab(void){
if(!this->_is_sub)
this->_set->_is.registerCallback(boost::bind(&ImageGenerator::callback,this,_1));
ros::CallbackQueue* mloop = ros::getGlobalCallbackQueue();
while(!this->_sht)
mloop->callAvailable(ros::WallDuration(0.1f));
this->_sht = true;
mloop = NULL;
this->_is_sub = true;
}
void ImageGenerator::callback(const sensor_msgs::ImageConstPtr &msg){
cv_bridge::CvImagePtr cv_ptr;
cv_ptr = cv_bridge::toCvCopy(msg);
this->_data = cv_ptr->image;
}
ImageGenerator::ImageGenerator(const NodeHandle & nh, const std::string & subscribe, const std::string & publish, const std::string & camera_info, function_type fun):_nh(nh),base::generator(_nh,subscribe,publish,camera_info),_fun(fun){ this->grab();}
ImageGenerator::~ImageGenerator(void){}
The issue which I want to solve is at
void ImageGenerator::grab(void)
It's :
this->_set->_is.registerCallback(boost::bind(&ImageGenerator::callback,this,_1));
the compiler answer :
error invalid use of incomplete type generator::it_set
The type is incomplete because the compiler hasn't seen the definition of that struct.
If you want to use the structs in subclasses of generator, you need to move their definitions inside the definition of generator in "base.hpp".