1

So I read about Plain Old Data classes (POD) , and decided to make my structs POD to hold data. For example, I have

struct MyClass {
    int ID;
    int age;
    double height;
    char[8] Name;
};


Obviously, to assign values to the struct, I can do this:

MyClass.ID = 1;
MyClass.age = 20;
...

But is there anyway to assign raw data, WITHOUT knowing the name of each field?

For example, My program retrieves field value for each column,, and I want to assign the value to the struct, given that i don't know the name of the fields..

MyClass c;

while (MoreColumns()) {
    doSomething( c , GetNextColumn() );    //GetNextColumn() returns some value of POD types
}

I'm assuming there's way to do this using memcpy, or something std::copy,, but Not sure how to start..

Sorry if the question is a bit unclear.

Community
  • 1
  • 1
user2436815
  • 3,455
  • 5
  • 27
  • 40
  • The question doesn't really make sense to me - why would you not know the names of the members? You know the type, so you know its members. After all, each member is a different type. – Joseph Mansfield Jul 25 '14 at 15:22
  • @user2436815 `char[8] Name;` isn't valid C or C++. This is java or c#-ism! Also please tag questions with precise tags, since C and C++ are very different languages when you get into actually coding programs in either language. – legends2k Jul 25 '14 at 15:31
  • Is there any reason your structs have to be PODs? – Neil Kirk Jul 25 '14 at 16:04
  • I am assuming you have some legitimate reason for assigning raw data to a field without knowing its name (after all, I have seen so little of the world to generalize). However, you would at least need to know the type of the field. Without that you could end up with assigning a float to a char[] and other strange problems. – Masked Man Jul 25 '14 at 16:17
  • @Happy Yes, I know the type of the fields.. Is there a way to assign raw data knowing the types..? – user2436815 Jul 25 '14 at 16:59
  • Chances are that what you are looking for is *serialisation* - saving the object to a file and creating it later from that file. Have a look at http://www.boost.org/doc/libs/1_55_0/libs/serialization/doc/index.html and see if it looks useful. – Christian Hackl Jul 25 '14 at 19:05

4 Answers4

0

You can use aggregate initialization:

MyClass c1 = { 1, 20, 6.0, "Bob" };
MyClass c2;
c2 = MyClass{ 2, 22, 5.5, "Alice" };

There is no general way to loop over the members of a struct or class. There are some tricks to add data and functions to emulate that sort of thing, but they all require additional setup work beyond just declaring the type.

aschepler
  • 70,891
  • 9
  • 107
  • 161
0

Since MyClass is an aggregate, you can use a brace-initializer to initialize all fields in one call, without naming any of them:

   MyClass m  { 
       1,
       2,
       42.0,
       { "Joseph" }
   };

However, given your description, maybe a POD is not a good idea, and you might want to design a class with accessors to set internal fields based on (for example) index columns.

quantdev
  • 23,517
  • 5
  • 55
  • 88
0

Maybe boost::fusion can help you with what you want to archive.
You can use the adapt macro to iterate over a struct. From the example of boost:

struct MyClass 
{
    int ID;
    int age;
    double height;
};

BOOST_FUSION_ADAPT_STRUCT(
    MyClass,
    (int, ID)
    (int, age)
    (double, height)
)

void fillData(int& i)
{
    i = 0;
}

void fillData(double& d)
{
    d = 99;
}

struct MoreColumns
{
    template<typename T>
    void operator()(T& t) const
    {
        fillData(t);
    }
};

int main()
{
    struct MyClass m = { 33, 5, 2.0 };
    std::cout << m.ID << std::endl;
    std::cout << m.age << std::endl;
    std::cout << m.height << std::endl;

    MoreColumns c;
    boost::fusion::for_each(m, c);

    std::cout << m.ID << std::endl;
    std::cout << m.age << std::endl;
    std::cout << m.height << std::endl;
}
mkaes
  • 13,781
  • 10
  • 52
  • 72
0

What you are trying to achieve usually leads to hard-to-read or even unreadable code. However, assuming that you have a genuinely good reason to try to assign (as opposed to initialize) raw data to a field without knowing its name, you could use reinterpret_cast as below (Link here). I don't recommend it, but just want to point out that you have the option.

#include <cstdio>
#include <cstring>

struct Target { // This is your "target"
    char foo[8]; 
};

struct Trap { 
    // The "trap" which lets you manipulate your target
    // without addressing its internals directly.
    // Assuming here that an unsigned occupies 4 bytes (not always holds)
    unsigned i1, i2;
};

int main() {
    Target t;
    strcpy(t.foo, "AAAAAAA");

    // Ask the compiler to "reinterpet" Target* as Trap*
    Trap* tr = reinterpret_cast<Trap*>(&t);

    fprintf(stdout, "Before: %s\n", t.foo);
    printf("%x %x\n", tr->i1, tr->i2);

    // Now manipulate as you please
    // Note the byte ordering issue in i2.
    // on another architecture, you might have to use 0x42424200
    tr->i1 = 0x42424242;
    tr->i2 = 0x00424242;

    printf("After: %s\n", t.foo);

    return 0;
} 

This is just a quick example I came up with, you can figure out how to make it "neater". Note that in the above, you could also access target iteratively, by using an array in "Trap" instead of i1, i2 as I have done above.

Let me reiterate, I don't recommend this style, but if you absolutely must do it, this is an option you could explore.

Masked Man
  • 1
  • 7
  • 40
  • 80