简体   繁体   中英

How to get struct member with a string using Macros C++

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM