Is there anyway I can pass a argument through a class like below for example.
class cat
{
public:
void dog(int ID, const char *value) // int ID I'd like to be the index array it was called from?
{
debug(ID, value);
}
};
cat cats[18];
cats[1].dog("value second arg, first arg auto filled from index array");
How about something like this:
class cat
{
public:
void dog(const char *value)
{
//debug(ID, value);
}
};
cat cats[18];
void cat_dog(int ID, const char *value)
{
debug(ID, value);
cats[ID].dog(value);
}
//cats[1].dog("value second arg, first arg auto filled from index array");
cat_dog(1, "value second arg, first arg auto filled from index array");
As mentioned in comment, you may alternatively use a member to store the index, and then no need to provide it in successive calls:
class cat
{
public:
cat(int index) : index(index) {}
void dog(const char *value) { debug(index, value); }
private:
std::size_t index;
};
And then initialize the array:
std::vector<cat> cats;
for (std::size_t i = 0; i != 18; ++i) {
cats.push_back(cat(i));
}
And then call any method:
cats[1].dog("text value, index 1 already stored in object");
Related
I'm working on modelling some hardware in SystemC (although that's not relevant to the question). The goal is to be able to declare a bunch of registers in a block (class) which are used directly in the class implementation. The external software/firmware will access the registers through a register map to decode based on address. So the HW block as part of its constructor will initialize the register map (not shown below). The issue arises from the fact that some registers need to trigger an action. To do this is seems appropriate to have method in the HW class that is called if the register is written.
The simplified class hierarchy is as follows
class regBase {
public:
regBase(uint64_t _address, std::string _name) :
m_address(_address),
m_name(_name) { }
regBase() {};
void setAddress(uint64_t _address) { m_address = _address;}
virtual void write(uint32_t newval) = 0; //virtual methods to be overridden in template
virtual uint32_t read(void) = 0;
virtual int size(void) = 0;
private:
uint64_t m_address;
std::string m_name;
};
template <class REG>
class hwRegister : public regBase
{
public:
uint32_t read(void) override
{
return m_val.value();
}
void write(uint32_t newval) override
{
m_val.setValue(newval);
}
int size(void) override
{
return (m_val.size());
}
private:
REG m_val;
};
typedef std::function<void(uint64_t, uint32_t)> writeCallback_t;
struct reg_entry {
reg_entry(int _size, regBase *_reg) :
m_reg(_reg), m_size(_size) {}
reg_entry() {}
regBase *m_reg;
int m_size;
writeCallback_t m_callback;
};
typedef boost::ptr_map<int, std::shared_ptr<reg_entry> > reg_map_t;
class RegMap {
public:
void write(uint64_t address, uint32_t val) {
auto it = m_register_map.find(address);
if (it==m_register_map.end())
{
BOOST_ASSERT_MSG(false, "Invalid address");
}
auto entry = *it->second;
entry->m_reg->write(val);
if (entry->m_callback)
entry->m_callback(address, val);
};
void setCallback(uint64_t address, writeCallback_t newcallback)
{
auto it = m_register_map.find(address);
if (it==m_register_map.end())
{
BOOST_ASSERT_MSG(false, "Invalid address");
}
(*it->second)->m_callback = newcallback;
};
void addReg(uint64_t address, regBase *reg) {
auto entry = std::make_shared<reg_entry>(reg->size(), reg);
entry->m_callback = nullptr;
entry->m_reg = reg;
m_register_map[address] = entry;
}
private:
reg_map_t m_register_map;
};
I want to in the implementation of HW block, add myReg to myMap and be able to add a callback if necessary for a given register. The issue is around the callback. Does the declaration of the callback look right? Do I need to use std::bind and placeholders?
Ok, updated with compiling code.
[this](uint64_t address, uint32_t val) { myCallback(address, val); } worked
struct my_reg_st {
uint64_t data;
uint64_t size(void) { return 8; };
void setValue(uint32_t val) { data = val; };
uint64_t value(void) {return data; };
};
class test {
public:
test() {
myMap.addReg(0, &myReg);
// use lambda function for callback. Note that use of intermediate f is only for readability
writeCallback_t f = [this](uint64_t address, uint32_t val) { myRegCallback(address, val); };
myMap.setCallback(0, f);
}
void myRegCallback(uint64_t address, uint32_t value);
void write(uint64_t address, uint32_t val) { myMap.write(address, val); };
private:
hwRegister<my_reg_st> myReg;
RegMap myMap;
};
I have a simple class which consists of a void pointer and an int (this is some sort of a boost::Variant educational project).
I also have a working copy constructor and a destructor.
But what grinds my gears is, how I would accomplish something like this:
Container cont1("some value"); //simple construction
Container cont2;
cont2.createLink(cont1); //this should initialize members with a reference (or something alike)
std::cout<<cont1; //yields "some value"
cont2.set(20); //setting this container should update the original container too, since I initialized with a reference (or smth alike)
std::cout<<cont1; //yields 20
This is the simplified version of the class:
class Container {
public:
Container(){}
Container(const std::string &val){var.type = STRING; var.data = new std::string(val);}
Container(int val){ /* same for int */}
Container(const Container &val){ /* do a memory copy */}
void set(int val){ /* set the value if type matches, otherwise allocate a new pointer */}
void set(const std::string &val){ /* the same as for int */}
void createLink(const Container &val){ /* somehow assign a reference or whatsoever */}
private:
typedef struct VAR {
int type = 0;
void *data = NULL; }
VAR var;
}
If I set the value of cont2 to a string (i.e. the same data type it holds at the moment), everything is fine, because the set would not allocate a new pointer and rather assign a new value.
But how do I make sure the pointer of cont1 updates if I assign a different value to cont2 and therefore have to allocate a new pointer?
Would I need something like shared_pointer?
Thanks for any insight!
EDIT:
I changed to function name to make it more clear what should happen.
There is a solution that only involves straight OO. You could create an interface for your variant type, and use double indirection to the variant instance to allow linked containers to share the same variant instance.
The reason double indirection is required is because of the way you want the set() method to automatically allocate a new variant instance if the new type doesn't match the original type. If we simply shared a pointer to the variant from both containers, then after set() creates a new variant instance, each container would be referring to different instances again.
To get around that, we can use a pointer to a pointer to a variant in the container instead.
Here is a possible way to define your variant interface, and how it could be subclassed:
typedef std::ostream Out;
struct BadType {};
struct Var {
virtual ~Var () = default;
virtual Out & print (Out &os) { return os << "(BadType)"; }
virtual void set (int) { throw BadType(); }
virtual void set (const std::string &) { throw BadType(); }
};
struct VarInteger : Var {
int data;
VarInteger (int v) : data(v) {}
Out & print (Out &os) { return os << data; }
void set (int v) throw() { data = v; }
};
struct VarString : Var {
std::string data;
VarString (const std::string &v) : data(v) {}
Out & print (Out &os) { return os << data; }
void set (const std::string &v) throw() { data = v; }
};
Here is how you could define your pointer to pointer, and how they could be initialized:
typedef std::shared_ptr<Var> VarPtr;
std::shared_ptr<VarPtr> varptr_;
static VarPtr make_var () { return std::make_shared<Var>(); }
static VarPtr make_var (int v) { return std::make_shared<VarInteger>(v); }
static VarPtr make_var (const std::string &v) {
return std::make_shared<VarString>(v);
}
VarPtr & var () { return *varptr_; }
const VarPtr & var () const { return *varptr_; }
Container () : varptr_(std::make_shared<VarPtr>(make_var())) {}
Container (int v) : varptr_(std::make_shared<VarPtr>(make_var(v))) {}
Container (const std::string &v)
: varptr_(std::make_shared<VarPtr>(make_var(v))) {}
And here is how your set() methods and createLink() method could be implemented.
void set (int v) {
try { var()->set(v); }
catch (BadType) { var() = make_var(v); }
}
void set (const std::string &v) {
try { var()->set(v); }
catch (BadType) { var() = make_var(v); }
}
void createLink (const Container &val) { varptr_ = val.varptr_; }
Demo
How about the following. Of course createLink cannot not take a const reference so I made it to take a non-const pointer.
class Container {
const int STRING = 0x0000001;
const int INT = 0x0000002;
const int LINK = 0x8000000;
public:
...
void set(int val){...}
void set(const std::string &val)
{
if (var.type == LINK)
{
reinterpret_cast<Container*>(var.data)->set(val);
}
else
...
}
void createLink(Container* val)
{
var.data = val;
var.type = LINK;
}
private:
typedef struct VAR {
int type = 0;
void *data = NULL;
};
VAR var;
};
There are a some important points to think about - relative lifetimes of the link and the linked is the most obvious one.
In this example code, the loop inside the two process() functions is duplicated. The only difference is that one is const and the other is not.
Is there a way to remove the code duplication, such that the loop only exists once? This is only an example but in the real code the loop is quite complex, so for maintenance reasons I only want the loop to exist once.
#include <iostream>
#include <vector>
typedef unsigned int Item;
typedef std::vector<Item *> Data;
struct ReadOnlyAction {
void action(const Item *i)
{
// Read item, do not modify
std::cout << "Reading item " << *i << "\n";
}
};
struct ModifyAction {
void action(Item *i)
{
// Modify item
std::cout << "Modifying item " << *i << "\n";
(*i)++;
}
};
void process(Data *d, ModifyAction *cb) {
// This loop is actually really complicated, and there are nested loops
// inside it three levels deep, so it should only exist once
for (Data::iterator i = d->begin(); i != d->end(); i++) {
Item *item = *i;
cb->action(item);
}
}
void process(const Data *d, ReadOnlyAction *cb) {
// This is the same loop as above, and so the code should not be duplicated
for (Data::const_iterator i = d->begin(); i != d->end(); i++) {
const Item *item = *i;
cb->action(item);
}
}
void incrementData(Data *d) {
// Here we modify the pointer, and need to loop through it
ModifyAction incrementItem;
process(d, &incrementItem);
}
void saveData(const Data *d) {
// Here we aren't allowed to modify the pointer, but we still need
// to loop through it
ReadOnlyAction printItem;
process(d, &printItem);
}
int main(void)
{
Data d;
// Populate with dummy data for example purposes
unsigned int a = 123;
unsigned int b = 456;
d.push_back(&a);
d.push_back(&b);
incrementData(&d);
saveData(&d);
return 0;
}
Please be aware that this is not a duplicate question. The following similar questions and answers are different:
123758 - only covers simple functions that return values, whereas this function calls other functions so the solutions given there do not work for this problem
23809745 - same issue, only covers simple functions that return values, answers do not work for this problem
If I attempt the solution given in those answers, it doesn't work but looks like this:
template <class CB>
void processT(const Data *d, CB *cb) {
// Single loop in only one location
for (Data::const_iterator i = d->begin(); i != d->end(); i++) {
const Item *item = *i;
// Compilation fails on the next line, because const Item* cannot be
// be converted to Item* for the call to ModifyAction::action()
cb->action(item);
}
}
void process(const Data *d, ReadOnlyAction *cb) {
processT(d, cb);
}
void process(Data *d, ModifyAction *cb) {
processT(static_cast<const Data *>(d), cb);
}
This is a simplified example, so it would be much appreciated if answers could focus on the problem (how to remove the duplicated loop from within the two process() functions) rather than comments about the design - changes to the design are fine of course if it removes the duplicate loop in the process.
Try something like this:
template <class IteratorType, class CB>
void processT(IteratorType first, IteratorType last, CB *cb)
{
while (first != last)
{
cb->action(*first);
++first;
}
}
void process(const Data *d, ReadOnlyAction *cb)
{
Data::const_iterator first = d->begin();
Data::const_iterator last = d->end();
processT(first, last, cb);
}
void process(Data *d, ModifyAction *cb)
{
Data::iterator first = d->begin();
Data::iterator last = d->end();
processT(first, last, cb);
}
Of course, in this simplified example, you could just use std::for_each() instead:
#include <algorithm>
void process(const Data *d, ReadOnlyAction *cb)
{
std::for_each(d->begin(), d->end(), &cb->action);
}
void process(Data *d, ModifyAction *cb)
{
std::for_each(d->begin(), d->end(), &cb->action);
}
I will assume the thing you care about is passing a const* to the action.
template<class Arg, class Data, class Action>
static void process_helper(Data *d, Action *cb) {
for (auto i = d->begin(); i != d->end(); i++) {
Arg item = *i;
cb->action(item);
}
}
void process(Data *d, ModifyAction *cb) {
process_helper<Item*>( d, cb );
}
void process(const Data *d, ReadOnlyAction *cb) {
process_helper<Item const*>( d, cb );
}
Now, if you lack C++11, write a traits class:
template<class Data>struct iterator
{ typedef typename Data::iterator iterator; };
template<class Data>struct iterator<const Data>
{ typedef typename Data::const_iterator iterator; };
template<class Arg, class Data, class Action>
static void process_helper(Data *d, Action *cb) {
for (typename iterator<Data>::type i = d->begin(); i != d->end(); i++) {
Arg item = *i;
cb->action(item);
}
}
which can extend to multiple nested loops.
Looks like if you make Data part of the template, like this, it compiles....
template <class D, class CB>
void processT(D d, CB *cb) {
for (auto i = d->begin(); i != d->end(); i++) {
auto *item = *i; // this requires c++0x e.g. g++ -std=c++0x
cb->action(item);
}
}
void process(const Data *d, ReadOnlyAction *cb) {
processT(d, cb);
}
void process(Data *d, ModifyAction *cb) {
processT(static_cast<const Data *>(d), cb);
}
Edit -- should work without the nasty cast as well, like;
void process(Data *d, ModifyAction *cb) {
processT(d, cb);
}
I think function process is like a "proxy" to call corresponding actions. The handling of the parameters and if they are const is owned by that actions. So the process function can be simplified like this (if c++11 is in place):
template<class DATA, class ACTION>
void process(DATA *d, ACTION *cb){
for (auto item : *d) {
cb->action(item);
}
}
class cat
{public:
void dog(int ID, char *value) // int ID I'd like to be the index array it was called from?
{
debug(ID, value);
}
}
cat cats[18];
cats[1].dog("value second arg, first arg auto filled from index array");
I want something similar to this.
include <vector>
class CatArray;
class Cat {
// This line means that the CatArray class can
// access the private members of this class.
friend class CatArray;
private:
static int ID;
public:
void dog(const char* value) {
// Use ID here any way you want.
}
};
int Cat::ID = 0;
class CatArray {
private:
std::vector<Cat> cats;
public:
explicit CatArray(unsigned int size) : cats(size) {}
Cat& operator [](unsigned int index) {
Cat::ID = index;
return cats[index];
}
};
But a little different. There are 18 Clients in a game and i need to basically do this. for eg, "Client 4 Chooses an option and the option gets called through the array index and than that way client 4 will call the function with the function holding the index 4"
Then cats[1] is not really a Cat object but a CatWithIndex object:
class Cat {
public:
void dog(size_t index,const char* value);
};
class CatWithIndex {
size_t index_;
const Cat &cat_;
public:
CatWithIndex(size_t index, const Cat &cat): index_(index), cat_(cat) {}
void dog(const char* value) {
cat_.dog(index_,value);
}
};
class CatArray {
private:
std::vector<Cat> cats;
public:
Cat& operator [](unsigned int index) {
Cat::ID = index;
return CatWithIndex(index,cats[index]);
}
};
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() ) ) );