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".
Related
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.
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 a problem to delete an "Member" from a "Group" by index:
#include <vector>
#include <string>
using namespace std;
class Member
{
public:
explicit Member(const string &name, const unsigned long &key) : m_name(name), m_key(key) {}
const string &getName() const {return m_name;};
const unsigned long &getKey() const {return m_key;};
private:
string m_name;
unsigned long m_key;
};
//------------------------------------------------------------------------
class Group
{
public:
explicit Group(const string &name) : m_name(name) {}
const string &getName() const {return m_name;};
void addMember(const Member &member) {m_member.push_back(member);};
const vector<Member> &getMember() const {return m_member;};
private:
string m_name;
vector<Member> m_member;
};
void main() {
vector<Group> group;
group.push_back(Group("Membergroup 1"));
group[0].addMember(Member("Mark", 123456));
group[0].addMember(Member("John", 234567));
group[0].getMember().erase(group[0].getMember().begin() + 1); //to delete John
}
Error: : passing 'const std::vector' as 'this' argument discards qualifiers [-fpermissive] group[_group].getMember().erase(group[_group].getMember().begin() + 1);
Can someone help me please?
The problem is here:
const vector<Member> &getMember() const {return m_member;};
The function getMember() (which I suggest to call as getMembers()) returns a const reference to the vector.
Since constness, the compiler prevents modifications.
You can fix just refactoring in the following way:
class Group
{
public:
// ...
const vector<Member>& getMembers() const { return m_member; }
vector<Member>& getMembers() { return m_member; }
// ...
I've been assigned the following template:
#include <map>
template <typename T>
class Catalog {
struct Item {
//..
};
std::map<int, Item*> items;
public:
Catalog(void);
Catalog(const Catalog&);
~Catalog(void);
bool IsEmpty(void) const;
int Size() const;
void Add(T*);
T* Remove(T*);
T* Find(T*);
typedef void (T::*pFunc) (const T&);
void Inspection(pFunc) const;
};
Next, there is an abstract Product class and three subclasses:
class Product {
protected:
unsigned int _id;
string _name;
public:
Product(const int& id, const string& name) : _id(id), _name(name) {};
virtual void Action(const Product& p) = 0;
virtual int hashCode() {
return _id*100;
};
unsigned int getId(void) const {return _id;};
string getName(void) const {return _name;};
};
class ProductA : public Product {
public:
ProductA(const int& id, const string& name) : Product(id, name) {};
virtual void Action(const Product& p) {
cout << "ahoj" << endl;
};
};
Finally, class ProductsCatalog that handles a Catalog instance:
class ProductsCatalog {
Catalog<Product> catalog;
public:
//..
void CatalogInspection(void) const {
catalog.Inspection(&Product::Action);
}
};
What I have trouble with is the Inspection method:
template <typename T> void Catalog<T>::Inspection(pFunc p) const {
for (std::map<int, Item*>::const_iterator it=items.begin(); it!=items.end(); ++it) {
it->second->Product->*p(*(it->second->Product));
}
};
I am getting the following error:
error C2064: term does not evaluate to a function taking 1 arguments
I've tried everything I could think of, without success. The following works as intended, but is obviously not abstract enough:
it->second->Product->Action(*it->second->Product);
Did you try
(it->second->Product->*p)(*(it->second->Product));
for calling the method?
The thread Calling C++ class methods via a function pointer seems to be related.
Consider the following example:
struct MyStruct {
int a;
int b;
};
I can use macros to set a member from an instance of the struct by doing this:
#define setVar(x,y) instance.x = y
then in any function I can say:
setVar(a, 4)
How can I send in a as a string to the macro? Is that also possible?
setVar("a", 4)
EDIT: There are a bunch of predefined structs with members that are all of type double. I only know what struct I am using by an XML config file that is passed in. After parsing, I have a bunch of strings that are a list of all the data members and values that need to be set. I need to use this list to set values for each of the members in the struct.
It is only possible if you define the struct itself using some macro, for example:
#define MY_STRUCT_STRUCTURE FIELD(a) FIELD(b) FIELD(d) FIELD(e) FIELD(f)
struct MyStruct {
# define FIELD(name) int name;
MY_STRUCT_STRUCTURE
# undef FIELD
bool setVar(char* fieldname, int val)
{
# define FIELD(name) if(strcmp(#name,fieldname)==0){name=val; return true;};
MY_STRUCT_STRUCTURE
# undef FIELD
return false; // name not found
}
};
int main()
{
MyStruct s;
s.setVar("a",1);
s.setVar("b",2);
s.setVar("f",100);
}
I have coded some quick and dirty code, but could give you some ideas, hope that helps. The main trick here is too use unions.
struct MyStruct
{
int a;
double b;
MyStruct()
: a(0), b(0) {}
};
MyStruct instance;
union value
{
long value_a;
double value_d;
} myvalue;
void blah_a(value v)
{
instance.a = v.value_a;
}
void blah_b(value v)
{
instance.b = v.value_d;
}
struct
{
(void)(*fn)(value);
const char* key;
}
lookup_table[] =
{
{ &blah_a, "a" },
{ &blah_b, "b" }
};
void setVar(const char* c, value v)
{
for (int i = 0; lookup_table[i].fn; i++)
if (c == lookup_table[i].key)
(*(lookup_table[i].fn))(v);
}
int main(int argc, char* argv[])
{
value v;
v.value_a = 6;
setVar("a", v);
return 0;
}
Might not be what you are looking for but an alternative solution to macros etc.. would just be some encapsulation and OO design. You can change the Field class to a template later and you will be able to represent anything basically.
You can create a class
class Field
{
public:
Field(const std::string& name, const std::string& type);
virtual ~Field(void);
std::string toString() const;
std::string getName() const;
int getValue() const { return value };
private:
std::string name;
std::string type;
int value;
};
And then a structure class
#pragma once
#include <boost/ptr_container/ptr_deque.hpp>
#include <string>
class Field;
class MyStructure
{
public:
typedef boost::ptr_deque<Field> FieldList;
typedef FieldList::iterator FieldListIter;
typedef FieldList::auto_type AutoField;
MyStructure(void);
MyStructure(const std::string& name);
virtual ~MyStructure(void);
void setName(const std::string& name);
std::string getName() const;
void addField( std::auto_ptr<Field> field );
std::string getFieldValue( const std::string& name ) const;
MyStructure::AutoField removeField( const std::string& name );
std::string toString(void) const;
private:
std::string struct_name;
FieldList fields;
};
And then to use it:
auto_ptr<MySructure> struct_a(new MySructure("StructName1",0) );
struct_a->addField( auto_ptr<Field> ( new Field( "Field1", 1 ) ) );
struct_a->addField( auto_ptr<Field> ( new Field( var_str1, 2) ) );
struct_a->addField( auto_ptr<Field> ( new Field( getName(), getVal() ) ) );